DATE, TIME, and DATETIME Fields

This chapter shows you how you can use DATE, TIME, and DATETIME fields in assignments, ACCEPT (validation), PRINT and SEND statements (Display).

DATE, TIME, and DATETIME Fields. 1

Introduction. 1

Section 1.  DATE fields. 1

Assignment To DATE Fields. 1

From Constants. 1

From Fields. 1

Initialising DATE fields with VALUE.. 1

Displaying DATE fields. 1

Assignment From DATE Fields. 1

Validating DATE Data. 1

Character input 1

Numeric Input 1

Date Arithmetic. 1

Date Comparisons. 1

Section 2.  TIME fields. 1

Assigning to TIME Fields. 1

From Constants. 1

From Fields. 1

Initialising TIME fields with VALUE.. 1

Displaying Time Data. 1

Assignment From TIME.. 1

Time Arithmetic. 1

Time Comparisons. 1

Section 3.  DATETIME fields. 1

Text Conventions. 1

 

Introduction

A field may be defined with type DATE, TIME, or DATETIME: -

DEFINE W DATA(

    Date1 DATE DPIC 'dd-MMM-yy',

    Date2 DATE DPIC 'dd.MMMM.yyyy',

    Date3 DATE DPIC 'dd/MM/yy',

    Date5 DATE DPIC 'yyyy.ddd',

    Date6 DATE DPIC 'ddd/yy',

    SpecialDate DATE VALUE 19631122);

    Time1 TIME DPIC hh:mm PM’,

    DateTime1 DATETIME );

 

By defining fields like this you make it clear to others, and to Jazz, the type of data that is in these fields: what it is used for, what values are valid, and how it should be displayed.   Jazz can ensure that it is set validly: for example

DEFINE X DATA(Date5 CHAR(9));

ACCEPT(W.Date5 = X.Date5) MESSAGE(Err.Msg);

will report an error if the CHAR(9) value in X.Date5 is not a valid date in format 'yyyy.ddd', such as 2016.060.

 

DATE and TIME fields are internally the same as INTEGER fields, in COBOL PIC S9(9) COMP, with initial value ZERO which means “No DATE (or TIME) value”  A DATETIME field is a combination: you can think of it as either a BIGINT field, or a GROUP containing a DATE and a TIME field. 

 

Whatever the DPIC (Display PICture), data in a DATE field is always stored as 8 digits: four year digits, two month, and two day.  Thus with value 2016.060 in X.Date5, W.Date5 is set to 20160229 (2016 is a leap year).

 

Refer to JazzLRM_Data.#Display_Options for information about DPIC.

 

TIME data is be stored as 9 digits: 2 for hour (00 to 23), 2 for minute (00 to 59), 2 for seconds (00 to 59), and 3 for milliseconds.

Section 1.  DATE fields

Assignment To DATE Fields.

A DATE field may be set from a constant, another DATE field, or (subject to various rules) a numeric or string field.   Date fields can also be set in Date Arithmetic.

From Constants

If you set a DATE field from a constant, then Jazz will interpret and validate the value when your program is checked, according to these rules: -

·         Numeric constants, without any separator characters.  For example: -

W.Date1 = 20160228;

The value is in order year, month, and day no matter what DPIC is used. 

 

·                     Numeric constants, with single separator character “.” or “/”.  If there is only a single separator character then the value is interpreted as an ordinal date, with the part before the separator being interpreted as year, and the part after the separator being interpreted as the day value from 1 to 366 (366 if a leap year).  If the year is less than 100, then the current century is added, as below.  The separator can be either “.” or “/”.  Thus

W.Date1 = 18.300;

#568 I Date Value is 27 Oct 2018

W.Date1 = 2018/300;

#568 I Date Value is 27 Oct 2018

The ordinal date is interpreted as a string, so leading zeros don’t have to be given:  18.25 is interpreted as day 25, not as day 250.

W.Date2 = 18.25;

#568 I Date Value is 25 Jan 2018

 

·         Numeric constants with two separator characters.  For example

W.Date1 = 04/3/2018;

#568 I Date Value is 04 Mar 2018

W.Date1 = 4/3/18;

#568 I Date Value is 04 Mar 2018

To resolve ambiguity between year and month the field’s DPIC is used. W.Date1 .has no explicit DPIC and so has the default DPIC 'dd mmm yy', so day comes before month.  W.Date2 has American-style DPIC 'mm dd yy'  and so 4/3 is interpreted as 3rd April, not 4th March.

W.Date2= 4/3/18;

#568 I Date Value is 03 Apr 2018

Note that the DPIC is used only to get the order of the sections Day, Month, and Year.  Even with DPIC 'dd mmm yy' you can give the month as a number, while with DPIC 'dd mm yy' you could give the month as “Jan” etc.  You can give more or fewer spaces, you do not have to give exactly the layout of the DPIC.

 

The date value is validated: for example: -

W.Date1 = 20170229;  [Not a leap year

#568 E Date Value invalid: Day Invalid

 

·         To reset a date to its initial value, or to zero indicating that the field contains no date, use

            W.Date1 = JAZZ.$Init;

or

            W.Date1 = JAZZ.$Null;

(You’ll simply write $Init or $Null, leaving it to Jazz to insert the qualification)

 

·         String constants. With a string value the value is checked as follows: -

1.         The string is split into parts, based on the separator character.  Jazz scans the string for characters {"/", "-", ".", " "} and the first of these characters found is used as the separator character.  With value

Date1 DATE DPIC 'dd-MMM-yy', …

W.Date1 = '27 May 17';

the blank between 27 and May is used as a separator, even though the DPIC uses “-”.  Both separator characters must be the same, so

W.Date1 = '27 May-17';

is invalid.

 

2.            If there is no separator character the string is interpreted as an eight-digit number, as described above.

3.            If there are only two parts, then the date is interpreted as an ordinal date, i.e. a year number followed by day-of-year.  Thus 2018.300 => 27th October, 2018.  The same rules as above for numeric constants are followed: the century may be omitted, and leading zeros for the day part are not necessary:  '18.25' is interpreted as day 25, not day 250, so this means 25th January 2018.

 

4.            The DPIC is used to determine the order, in cases where this is ambiguous.  Thus with a value

W.Date1 = '4 3 17';

does this mean the 4th of March 2017 (British), or the 3rd of April 2017 (American), or the 17th of March 2004 (possibly Japanese)?  The DPIC resolves this ambiguity as described for numeric constants with separators.

From Fields

You can set DATE fields from

·         another DATE field,

·         an INTEGER field

·         a DECIMAL field with at least 8 digits and no decimal fraction

·         a DECIMAL field defined DECIMAL (7,3) or DECIMAL(5,3), or

·         a CHAR or VARCHAR field. 

 

If the source type is not DATE then it is recommended that data is assigned using an ACCEPT statement: for example
            ACCEPT (W.Date1 = W.DecimalField);
instead of using a simple assignment
            W.Date1 = W.DecimalField;

In both cases Jazz will check the input, but errors may not be reported unless ACCEPT is used.

 

Rules are as described above for assignments BUT you need to be careful to ensure that DECIMAL fractions are handled as you want.  For example: -

            W.Date1 = '18.25';  means the 25th day of [20]18.

            W.Date1 = 18.25; interprets “18.25” as a string, and gives the same value.

Both assign the 25th day of January to the date.  However DECIMAL fractions are handled according to the normal rules of maths.  Thus

            DNbr2 DECIMAL(7,3),

            W.DNbr2 = 2018.25; 

If you follow this with an assignment to a date field: -

            W.Date1 = W.DNbr2;

the date is not the 25th January, it is some time in September.  The first assignment is a normal arithmetic assignment: there’s nothing in it to say that this value is intended to be a DATE, so it assigns 2018 and 25/100 to W.DNbr2, and is identical in value to

            W.DNbr2 = 2018.250; 

To have the fractional part interpreted as days-of-the-year you must write leading zeros and avoid fractions larger than 366.

W.DNbr2 = 2018.025;  [25th Jan

W.Date1 = W.DNbr2;

·         Date values can also be set with an expression of the form  Date1 = Date2 +/- value, for example

W.Date1 = W.Date2 + 30;

See Date Arithmetic below for more information.

Initialising DATE fields with VALUE

Like other fields a DATE field can be defined with an initial value: -

DEFINE W DATA(

    Date1 DATE DPIC 'dd MMM yy' VALUE 20180304,

#568 I Date Value is 04 Mar 2018

Initial values may be an eight-digit number, in format yyyymmdd, as above, or a decimal number which will be interpreted as an ordinal date: -

    DateG DATE VALUE 18.300,

#568 I Date Value is 27 Oct 2018

or a string value giving a date as if printed with the field’s DPIC: -

    DateB DATE DPIC 'MM dd yy' VALUE '4 3 18',

#568 I Date Value is 03 Apr 2018

In all cases message #568 will tell you how the date is interpreted, to avoid confusion between American and other date forms, and the COBOL fields will be an integer (COMP S9(9) VALUE 20180304 if the date is 4th March 2018).

Displaying DATE fields

When a DATE field is printed, or displayed on a screen, then it is formatted according to its DPIC.  Refer to JazzLRM_Data.#Display_Options for information about DPIC.

Assignment From DATE Fields.

A DATE field may be assigned to

·         Another DATE field

·         A numeric variable

Assigning a DATE to a number will assign an eight-digit numeric value such as 20180124.  A message will be produced if the numeric variable has fewer than 8 digits.  If the target number has a suitable DPIC then the value will be easy to interpret: for example

DEFINE X DATA(Number INTEGER DPIC '9999,99,99');

DEFINE W DATA(Date1 DATE DPIC 'dd-MMM-yy');

X.Number = W.Date1;

PRINT (W.Date1, X.Number);

resulting in output like this: -

*-Date1-* *-Number-*

29-Feb-16 2016,02,29

 

·         A CHAR or VARCHAR variable.  The date field will be formatted to a string according to its DPIC.  For example: -

DEFINE W DATA(

    Date2 DATE DPIC 'dd.MMMM.yyyy');

DEFINE X DATA(

    Date2 CHAR(17);

W.Date2 = 20171217;

X.Date2 = W.Date2;

assigns value '17.December.2017' to X.Date2.

 

Refer to JazzLRM_Data.#Display_Options for information about DPIC.

Validating DATE Data

When variable data is assigned to a DATE field it is recommended that you use ACCEPT, rather than a simple assignment, as this will validate that the assigned data is actually a date, setting $Error and producing messages when the source field cannot be converted to a valid date.  Refer to JazzLRM_Accept for more information about ACCEPT.  As with any other ACCEPT statement, several validations and assignments may be combined into one statement: -

ACCEPT(W.Date1 = X.Date1, W.Date5 = X.Date5) MESSAGE(Err.Msg);

and assignment targets (W.Date1, W.Date5 in the example above) may be omitted if the target is implied or there’s no assignment because a DATE field is being validated in place.

Character input

If the source fields (X.Date1, X.Date5 in the example above) have type CHAR or VARCHAR then if possible their value is converted into a date with these rules: -

1.            Firstly Jazz looks for possible separator characters: “/”, “-”, “.”, or “ ”.  The first of these to be found is chosen as the separator character, even if it is not the leftmost.  Thus if the string contains “12 3/4” then Jazz will use “/” as separator because it looks for this first. 

 

2.            The string value is then broken into parts using the separator character.  Thus the string above would be broken into two parts, “12 3” and “4”.   More realistically,

“12345678bbbb”    =>    1 part, “12345678”

“18.155”          =>    2 parts, “18”, “155”

“1/2/3”           =>    3 parts, “1”, “2”, “3”
           

3.            If one part, then the string is interpreted as an eight digit number in format yyyymmdd.   12345678 is invalid: 56 is greater than 12, and no month has 78 days.  However a value 20180325 would be valid.

4.            If two parts the string value is interpreted as an ordinal date.  For year values less than 100 the century added, thus 10 becomes 2018.  The day-of-year must be a number from 1 to 366.  Thus 18:155 is the 155th day of 2018, i.e. 4th June 2018.

5.            If three parts, then the DPIC of the target field is used to give the relative order of day, month, and year.  Thus with
            DPIC 'dd MMM yyyy'   :           “1/2/3” means 1st Feb, 2003
           
DPIC 'MM dd yy'         :           “1/2/3” means 2nd January 2003.
Note that the Jazz interprets the date as flexibly as possible, so that you don’t can give a numeric month when the
DPIC specifies an alphabetic abbreviation or the full month name, and vice versa.   Day must be a number from 1 to the maximum for the month, month must be a number from 1 to 12 or one of the valid month abbreviations or names, and year must be a number from 100 to 9999.  If the year is < 100, the current century is added.  None of the numeric values may be negative.

 

6.            If there are four or more parts, then the value is invalid.

Numeric Input

A number is first range-checked: it must not be less than 10000101  (1 Jan 1000) or greater than 99991231  (31st December 9999).  If it survives this check, then the value of Month (digits 5-6) and Day (7-8) are checked as above.

Date Arithmetic

You can write simple date arithmetic assignments of the form

            Date1 = Date2 operator Value;

for example to add 30 days

W.Date1 = W.Date2 + 30;

 

To increase or decrease a date you can use the assignment operators += and -=.  Thus

            W.Date1 += 30;

is equivalent to

W.Date1 = W.Date1 + 30;

 

The operator may be + or -, but not multiplication (*) or division (/).

 

The difference value may be a constant or a field.  Fields must have one of the types valid for assignment to a date.  Difference values are interpreted as described above for date assignment, being broken into parts by the separator character, except that any (or all) of the year, month, and day sections may be zero.  Thus

W.Date1 = W.Date2 + 2.300;

adds 2 years and 300 days to W.Date2. With three-part dates DPIC resolves the ambiguity between British-form dates (Day, Month, Year) and American-form dates (Month, Day, Year), so that if W.Date2 has DPIC 'mm dd yy' then

      W.Date1 = W.Date2 + 2/3/0;

adds two months and three days to W.Date2.

 

The assignment may only have a single operator and may not use parenthesis.  Thus

W.Date1 = W.Date2 + W.NBR * 2;

is not valid.

 

The logic of Date arithmetic is

1.            The Date Difference value is converted to a GROUP with four SMALLINT values representing the number of years, months, days-of-month and days-of-year to be added or subtracted.  This value is like a DATE field except that any or all parts may be zero.

2.            Logic is as follows.

a.    Add/Subtract years

b.    Add/Subtract months  

If months < 1 (-) then

Subtract 1 from years, add 12 to months

elseif Months > 12 (+) then

Add 1 to years, subtract 12 from months

c.     Set days-in-Feb to 29 if a leap year, else 28

d.    Add/Subtract Days

If Days < 1 (-) then

Subtract 1 from months

If months < 1 then

Subtract 1 from years, add 12 to months

Add days-in-month to Days

Elseif Days > days-in-month (+) then

Subtract days-in-month from Days

Add 1 to months

If months > 12 then

Add 1 to years, subtract 12 from months

3.            If the date difference was given as a simple number, or an ordinal date, then the days part will be in the days-of-year field.  With date assignment,

                        W.Date1 = 18.155;

W.Date1 is set to 04 Jun 2018, but adding 155 days to a date is not the same as adding 4 days and 6 months, as the result of date arithmetic depends on the starting date to which the difference is added or subtracted.

Date Comparisons

DATE fields can be used in comparisons.  All the usual comparison operators =, <>, >, >=, <, <=, are available.

Section 2.  TIME fields

TIME data will be stored as 9 digits: 2 for hour (00 to 23), 2 for minute (00 to 59), 2 for seconds (00 to 59), and 3 for milliseconds. Within COBOL and Jazz, it is stored as a 4 byte field like an INTEGER, but in SQL the last three digits (milliseconds) are not carried in DB2 (and presumably Oracle), and the value will be rounded up if milliseconds is > 500.

Assigning to TIME Fields

A TIME field may be set from a constant, another TIME field, or (subject to various rules) a numeric or string field.   TIME fields can also be set in Date Arithmetic.

From Constants

Constants are written in order Hours, minutes, seconds, and milliseconds.  Whatever form you write – time, number, string – it will be converted to a time constant.  For example, if you write
            W.T1 = 154512345;
it will be changed to

W.T1 = 15:45:12.345;

when [Check] is clicked, except for value 0 which stays as 0, assigning a time of 00:00:00.000.

 

The constant must be a valid time.  If not, there will be one or more messages, and the invalid sections of the time will be set to zero.  For example

W.T1 = 127862789;

becomes

W.T1 = 12:00:00.789;

#734 E Minutes < 0 or > 60

#734 E Seconds < 0 or > 60

Click [Check] again if you want to accept the 00 values, or enter the correct values.

From Fields

You can set TIME fields from another TIME field, or

·         a compatible numeric field: INTEGER,  DECIMAL(9), PIC ‘999999999’

·         From a CHAR or VARCHAR field, which is interpreted as a number.  

 

The value assigned to a TIME field must be a valid time:  all parts must be numeric, and value in the range

Hour:   0 to 23,

Minute: 0 to 59

Second: 0 to 59

Millisecond: 0 to 999.  

An assignment of a compatible field to a TIME is checked to ensure that the compatible field actually contains a TIME value.  For example, with

DEFINE W DATA(

    T1 TIME,

    Int INTEGER,

this assignment produces message #737: -

W.T1 = W.Int;

#737 W W.Int may be invalid.  Check JZTMVS.Error after this assignment

If you are not confident that W.Int will always have a valid time value, then you should follow this statement with some logic starting with

IF JZTMVS.Error THEN;

   

END IF;

 

Assignments from compatible numeric fields may contain values like 123456789 and from CHAR or VARCHAR fields values like ’123456789’.  In addition, assignment from CHAR or VARCHAR This form of assignment may include DPIC, in which case the character string is interpreted according to the DPIC of the target TIME field, e.g.
      W.T5 = W.CH DPIC;
interprets the value in W.CH according to W.T5’s DPIC.

Initialising TIME fields with VALUE

When you use VALUE with a TIME field, the value is validated and converted to a time constant.  For example, you might write

DEFINE W DATA(

    T1 TIME VALUE 12:34:56.789,

    T2 TIME DPIC 'hh:mm PM' VALUE 123456789,

    T3 TIME VALUE '123456789',

    T4 TIME VALUE '12:34:56.789',

    T5 TIME DPIC 'hh:mm' VALUE '12:34',

    Last INTEGER);

 

[Check] changes this to

DEFINE W DATA(

    T1 TIME VALUE 12:34:56.789,

    T2 TIME DPIC 'hh:mm PM' VALUE 12:34:56.789,

    T3 TIME VALUE 12:34:56.789,

    T4 TIME VALUE 12:34:56.789,

    T5 TIME DPIC 'hh:mm' VALUE 12:34:00.000,

    Last INTEGER);

 

If the value is not a valid Time then there will be a message, and the invalid part will be set to 00.

Displaying Time Data

For TIME fields, DPIC uses these symbols

hh                    Represents the hour, using the 24 hour clock, e.g. 13 = 1 PM.  Values 0 to 23.

mm                  Minutes.  Values 0 to 59.

ss                     Seconds.  Values 0 to 59.

mmm              Milliseconds.  Values 0 to 999.   Depending on the system clock, this value may be approximate.

PM                  Will print hours as 0-12, and display AM or PM depending on whether the hour is >= 12.   Hours 00 to 09 will omit the leading zero.

 

mm and mmm must be lower case to distinguish it from Month values in a DATE value, and hh and ss must also be lower case. PM must be upper case.

 

Blank (“ “ or B), period (.), and colon (:) are separator characters.  The default DPIC is hh:mm:ss.mmm

 

For example: -

DEFINE W DATA(

    T1 TIME,

    T2 TIME DPIC 'hh:mm:ss.mmm',

    T3 TIME DPIC 'hh:mm PM',

    T5 TIME DPIC 'hh:mm PM',

    T6 TIME DPIC 'hh:mm:ss.mmmBPM',

    CH CHAR(12),

    INT INTEGER;

W.T1 = 15:45:12.345;

W.T2 = W.T1;

W.T3 = W.T1;

W.T5 = 08:15:30.123;

W.T6 = W.T1;

PRINT (W.T1, W.T2, W.T3, W.T5, W.T6) FIELDTABLE;

Prints: -

Field  VALUE     

W.T1  15:45:12.345

W.T2  15:45:12.345

W.T3   3:45 PM   

W.T5   8:15 AM   

W.T6   3:45:12.345 PM

In all cases the actual value handled by COBOL is a simple integer, e.g.

002890     MOVE 154512345 TO T1 OF W.                                   ATP

 

If the DPIC does not include mmm to display milliseconds, then the value is rounded up if milliseconds is greater than 500.  Thus with

DEFINE W DATA(

    T1 TIME DPIC 'hh:mm:ss',

W.T1 = 15:45:12.745;

prints as

W.T1  15:45:13

 

This would also be the value stored in DB2 if W.T1 is assigned to a field in the DB record and this record is written to DB2.   However in your Jazz and COBOL program, the data retains its full 9 digit precision, including 745 milliseconds.

Assignment From TIME

TIME fields can be assigned to INTEGER,  DECIMAL(9), PIC ‘999999999’ fields, and to CHAR and VARCHAR fields.   For example

              W.INT = W.T1;

would assign value 154512345 to W.INT.  For DECIMAL and PIC the target field must have 9 digits, and no decimal fraction.

 

For assignment to CHAR and VARCHAR fields the TIME field’s DPIC determines the format of the output.

Time Arithmetic

TIME values can be added and subtracted, with statements like

W.TR1 = W.T1 + W.T2;

W.TR2 = W.T2 - W.T1;

W.TR3 = W.T1 - W.T2;

W.TR4 = W.T1 + 12:34:56.789;

If a constant is added or subtracted, it must be written as a Time Constant, and be the 2nd operand.

 

The shorthand operators += and -= can be used to add or subtract a value from a TIME.  These are equivalent: -

W.T1 = W.T1 + W.T2;

W.T1 += W.T2;

So are these: -

W.T1 = W.T1 + 12:34:56.789;

W.T1 += 12:34:56.789;

 

Addition may result in a value greater than 23:59:59:999, and subtraction may result in a value less than 00:00:00.000.  If so, the Hour part is set to the value MOD 24, and a non-zero overflow value results.  You may choose to test the overflow field JZTMAR.OFlow, this will be -1 if value would have been less than 00:00:00.000, and +1 if the value exceeded 23:59:59:999

Time Comparisons

TIME fields can be used in comparisons.  All the usual comparison operators =, <>, >, >=, <, <=, are available.

Section 3.  DATETIME fields

Not yet implemented, except for definition.  A DATETIME field is like a GROUP defined

    DTGroup GROUP,

        DatePart DATE,

        TimePart TIME,

        end GROUP);

except that adding or subtracting time from Timepart does not affect Datepart, whereas adding or subtracting time from a DATETIME field can change the date part of the DATETIME field.

 

Assignment between DATETIME and DATE or TIME fields is permitted: -

·         Datetime = Date;   Datepart set, Timepart is set to 00:00:00:000

·         Datetime = Time;   Date set to 0, Timepart set.  E-level message

·         Date = Datetime;  Datepart is assigned, Timepart ignored

·         Time = Datetime;  Timepart is assigned, Datepart ignored.

·         For arithmetic with DATETIME fields and a TIME field the overflow is rolled into DATE part of the calculation, resulting in a day being added or subtracted to the date, and no message is produced.

Text Conventions  

Some material is like this, written in the normal text, but coloured green. This is material that hasn’t been implemented yet. As this material is implemented the text is reviewed, changed as necessary, and changed to normal text colour.