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. 2

Assignment To DATE Fields. 2

Initialising DATE fields with VALUE.. 3

Assignment From DATE Fields. 3

Validating DATE Data. 4

Date Arithmetic. 5

Date Logic. 6

Section 2.  TIME fields. 6

Section 3.  DATETIME fields. 6

Text Conventions. 6

 

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,

    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 and DATETIME fields are not implemented yet, except for definition. 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.

Section 1.  DATE fields

Assignment To DATE Fields.

A DATE field may be set from

·         Another DATE field

 

·         A constant.   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 separator character “/” between year, month, and day

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

 

If there is only a single separator character then the value is interpreted as a Julian 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 365 (366 if a leap year).  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 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 two or three parts, based on 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 -.  Jazz scans the string for characters {"/", "-", ".", " "} and the first of these characters found is used as the separator character.  Both separator characters must be the same: -

W.Date1 = '27 May-17';

is invalid.

 

2.                  If there are only two parts, then the date is interpreted as a Julian date, i.e. a year number followed by day-of-year.  Thus 2018.300 => 27th October, 2018.  The century may be omitted: the same value results from 18.300. 

 

3.                  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: the parts of the DATE appear in order Day, Month, Year

 

·         A DATE, Numeric or string (CHAR or VARCHAR) variable.   If the 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 using the same rules as above but errors are not reported unless ACCEPT is used.

·         An expression of the form  Date1 = Date2 op 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 a Julian 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).

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 an eight-digit number using the DPIC of the target field.  The positions of year, month, and day sections is the same as their positions in the DPIC except that code MMMM, meaning the full month name, implies 8 characters, not 4, so that with DPIC 'dd.MMMM.yyyy' the year value will be in positions 12-15.

 

Separator characters (“ ”, “.”, “/”, “,”) are counted but not checked: for example there must be one character between the day and the month with this DPIC, but it doesn’t have to be a period.

 

First the year is obtained.  If the year format is given as yy then a value from 01 to 99 is expected, and today’s century will be used.  The year, either as 2 or 4 digits, must be numeric.  Leading zeros are required: “01”, not “1b”.  From the year value it can be determined whether this is a leap year.

 

For DPICs with month, the month value is obtained by: -

·         DPIC MM: a numeric value from 01 to 12 is expected.  Leading zeros are required.

·         DPIC MMM: a short (3 character) month name, “Jan”, “Feb” … “Dec” is expected.  Jazz looks up JZSMth.SMTH to find this.

·         DPIC MMMM: a full (8 character) month name, “January”, to “December” is expected.  Jazz looks up JZLMth.LMTH to find this.

·         The Day value must be a numeric value from 01 to the maximum for the month: 30 or 31 except for February, whose maximum is 29 in leap years, otherwise 28

 

For Julian DPICs the day value is 001 to 365 (or 366 for a leap year), and the month is calculated from the day.

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

W.Date1 = W.Date2 + 30;

 

·         If the value is a constant value then it follows the same rules as above for assignment to a date, except that any (or all) of the year, month, and day sections may be zero.  Separator characters are used to separate year, month, and day, or year and day if the Julian form is used.  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.

 

·         If the value is a field, then it may have INTEGER, SMALLINT, DECIMAL, CHAR, or VARCHAR format. 

o                    For INTEGER, SMALLINT, and DECIMAL fields without decimal fraction, the value may not exceed 365 and is interpreted as a number of days. 

o                    For DECIMAL fields with fraction the value is interpreted as a Julian-form date, with the fractional part being days (0 to 365) and the whole-number part being years.  

o                    For CHAR and VARCHAR fields, the value is interpreted as described above for simple assignment of a string field to a date. 

 

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

 

·         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 three SMALLINT values representing the number of years, months, and days to be added or subtracted.  This value is like a DATE field except that years, months, and days may all 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

Date Comparisons

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

Section 2.  TIME fields

Not yet implemented, except for definition.  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.  

 

As with DATE fields, assignment of constant data will be validated by Jazz when the program is checked, and variable data can be validated with ACCEPT. 

 

DPIC formats for TIME data will be defined. 

 

Built-in functions $Hour, $Minute, $Second, and $MSecond will extract the various parts of a time.

 

TIME arithmetic will be supported: details to be defined.

 

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

·         Datetime &= Time; Datepart unchanged, Timepart set.

·         Date = Datetime;  Datepart is assigned, Timepart ignored

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

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.