|
» |
|
|
|
by M Gopalakrishnan Commercial
Systems Division This release of the MPE/iX operating system has enhanced intrinsics
for handling date formats.
These
intrinsics are targeted to support widely used existing date formats
in MPE/iX and three new date formats. The date intrinsics are broadly categorized as follows: HPDATECONVERT—Converting
dates from one supported format to another. HPDATEFORMAT—Converting
the supported format dates to the display formats desired by the
user. HPDATEDIFF—Determining
the number of days that separate two given dates. HPDATEOFFSET—Adding/subtracting
an offset (days) to/from the given date. HPDATEVALIDATE—Validating
the given date for conformance to a supported date format. HPCALENDAR,
HPFMTCALENDAR—Using
the new 32-bit HPCALENDAR
format.
The following sections will discuss various date formats and
the syntax and semantics of new date intrinsics. COBOL and Pascal
programs using these intrinsics are provided as examples. Existing Date Formats | |
Existing date formats that are widely used are summarized
in the following table, "Existing Date Formats."
The column "Sortable?" indicates whether the dates
can be sorted (either numerically or lexicographically depending
on how they are stored). The last column "Y2K Ready?"
indicates whether dates in the format under consideration can be
used to represent dates beyond 1999-12-31. The column "#Bytes"
represents the number of bytes required to store the date format. Table 9-2 Existing
Date Formats Storage Type | # Bytes | Explanation | Sortable? | Y2K Ready? |
---|
longint [1] | 8 | Microseconds since 1970-01-01 | yes | yes | | | (MPE time-stamp) | | | integer | 4 | Upper 2 bytes: year | yes | yes | | | next byte: month of year | | | | | bottom byte: day of month | | | integer | 4 | Upper 2 bytes: year | yes | yes | | | bottom 2 bytes:
day of year | | | integer | 4 | Seconds since 1970-01-01 | yes | yes | | | (POSIX.1 time()
format; valid through 2038-01-18) | | | shortint | 2 | Upper 7 bits: #years since 1900 | yes | yes | | | Lower 9 bits: day of the
year | | | | | (CALENDAR
format; valid up to 2027-12-31) | | | integer | 4 | YYMMDD
date | yes | no | integer | 4 | MMDDYY date | no | no | integer | 4 | DDMMYY date | no | no | ASCII [2] | 6 | YYMMDD date | yes | no | ASCII | 6 | MMDDYY date | no | no | ASCII | 6 | DDMMYY date | no | no | ASCII | 6 | YYMMDD date YY:MM3000 date [3] | yes | yes | ASCII | 6 | MMDDYY date YY:MM3000 date | no | yes | ASCII | 6 | DDMMYY date YY:MM3000 date | no | yes |
New Date Formats | |
Three new date formats are listed in the table, "HP
Standard Formats." The first format is an integer representation
of the ISO 8601 date format. The second is an ASCII representation
of the same. The last date format is an extension of the existing
16-bit CALENDAR
date format to a 32-bit format. These date formats will be referred
to as "HP Standard Formats." Table 9-3 HP
Standard Formats Storage Type | # Bytes | Explanation | Sortable? | Y2K Ready? |
---|
integer | 4 | YYYYMMDD date | yes | yes | ASCII | 8 | YYYYMMDD date | yes | yes | integer | 4 | Upper 23 bits: #years since 1900 | yes | yes | | | Bottom 9 bits: day of the
year. | | | | | (Extension of the existing CALENDAR
format.) | | |
Supported Date Formats | |
The "HP Standard Formats" and "Existing
Date Formats" are combined in the following table, "Supported
Date Formats." Each date format is assigned a date type
code. The date intrinsics support these date formats and date type
codes. Table 9-4 Supported
Date Formats Date Type Code | Storage Type | # Bytes | Explanation | Sortable? | Y2K Ready? |
---|
1 | longint | 8 | MPE time-stamp | yes | yes | | | | (microseconds
since 1970-01-01) | | | 2 | integer | 4 | Upper 2 bytes: year | yes | yes | | | | next byte: month of year | | | | | | bottom byte: day of month | | | 3 | integer | 4 | Upper 2 bytes: year | yes | yes | | | | bottom 2 bytes: day of year | | | 4 | integer | 4 | Upper 23 bits: #years since 1900 | yes | yes | | | | bottom 9 bits: day of the
year. | | | | | | (analogous to the existing CALENDAR
format.) | | | 10 | integer | 4 | Seconds since 1970-01-01 | yes | yes | | | | (POSIX.1 time()
format; valid through 2038-01-18) | | | 14 | shortint | 2 | Upper 7 bits: #years since 1900 | yes | yes | | | | Lower 9 bits: day of the
year | | | | | | (CALENDAR
format; valid up to 2027-12-31) | | | 15 | integer | 4 | YYMMDD date | yes | no | 16 | integer | 4 | MMDDYY date | no | no | 17 | integer | 4 | DDMMYY date | no | no | 18 | integer | 4 | YYYYMMDD date | yes | yes | 25 | ASCII | 6 | YYMMDD date | yes | no | 26 | ASCII | 6 | MMDDYY date | no | no | 27 | ASCII | 6 | DDMMYY date | no | no | 35 | ASCII | 6 | YYMMDD date YY:MM3000 date[1] | yes | yes | 36 | ASCII | 6 | MMDDYY date YY:MM3000 date | no | yes | 37 | ASCII | 6 | DDMMYY date YY:MM3000 date | no | yes | 38 | ASCII | 8 | YYYYMMDD date | yes | yes |
Special Date Values | |
Special date values to represent UNKNOWN, INVALID, NEVER,
NEEDED, EXPIRED, and ILLEGAL
dates are defined for dates in "HP standard formats."
The following table captures this date value information. The other
date formats have been in existence for some time and hence the
special date values are not defined for them. These special dates,
when passed to the HPDATEFORMAT
intrinsic, will result in a corresponding output string. For example,
passing "00000103" to HPDATEFORMAT
will result in the output string: "NEEDED". When special dates are passed to HPDATECONVERT,
HPDATEOFFSET,
and HPDATEDIFF
intrinsics as input dates, an error status is returned and the output
date is initialized to a binary zero value or a blank string, depending
on the date type of the output date. Table 9-5 Special
Date Values DataType | Format | Un- known | Invalid | Never | Needed | Expired | Illegal |
---|
4 | YYYYDDD | 0 | 0000367 | 0000368 | 0000369 | 0000370 | 0000371 | 18 | YYYYMMDD | 0 | 00000101 | 00000102 | 00000103 | 00000104 | 0000105 | 38 | YYYYMMDD | "blank" | "0000010" | "00000102" | "00000103" | "00000104" | "0000105" |
New Date Intrinsics | |
The date intrinsics support dates in the range 0001-01-01
through 9999-12-31. They use the Gregorian calendar for all calculations
beyond 1753. The calendar followed by the intrinsics ignores the
fact that calendars in different countries changed at different
times and some dates were dropped from the calendar (around the
year 1753). The validity of dates prior to 1753 cannot be guaranteed.
All intrinsics accept byte-aligned input/output date parameters,
and all these intrinsics are NM callable. On an error, the intrinsics initialize the output parameters
to either a binary zero or a blank string depending on the type
of the parameter. Though the date type "4" can represent years
beyond 9999, a year beyond 9999 (which needs five digits/characters)
is considered an error. It is recommended that character array based output date parameters
are initialized to blanks before passing them as arguments to these
intrinsics. New errors and warnings are documented in the System Message
Catalog, SYSCAT.PUB.SYS,
under the date intrinsics subsystem number 529. This intrinsic converts the dates from one supported format
to another. Syntax I32V * I32V * I32 I32V HPDATECONVERT(inputcode,inputdate,outputcode,outputdate,status,cutoff)
|
Parameters - inputcode
is a 32-bit signed integer by value. The value should be one of the date type codes listed in the
table, "Supported Date Formats." - inputdate
varies for type by reference. The interpretation depends upon the value of inputcode.
See the table, "Supported Date Formats," for the
supported date codes and their layouts. - outputcode
is a 32-bit signed integer by value. The value should be one of the date type codes listed in the
table, "Supported Date Formats." - outputdate
returns the date as per the format chosen by the
outputcode parameter. See the table, "Supported Date Formats,"
for the supported datecodes and their layouts. - status
is the HPE_STATUS
parameter through which the error codes are returned. A value of
0 indicates no error and no warnings. - cutoff
is a 32-bit signed integer by value (optional). This is used in validating the input parameter when the input
date has two-digit year. This is a required parameter for dates
with two-digit years. In all other cases, this parameter is ignored. If the cutoff parameter is given
as -1, the value of the CI environment variable HPSPLITYEAR
is used as the cutoff year. This parameter's value should be in the range 0 .. 100.
If the value of the parameter is 50, two digit years in the range
0 .. 49 will translate to 200 .. 2049
and those in the range 50 .. 99 will be translated
to 1950..1999. If you specify the cutoff
year as 70, the mapping will be 0 .. 69 as 2000 .. 2069
and 70 .. 99 as 1970 .. 1999.
You can use this routine to format the dates that can be combinations
of display formats as explained below. Many of these elements are
taken from ALLBASE/SQL date formats. You can convert dates in the "Supported Date Formats"
to a display string of your choice (with restrictions). The HPDATEFORMAT
intrinsic will accept these format strings. The format specification
strings can have the following syntax: Syntax [{FormatElement}{Punctuation}]
|
Table 9-6 Valid
Parameters for FormatElement CC | Century (01 to 99) | YYYY | Year (0001 to 9999) | YY | Year of century (00 to 99) with leading
zeros suppressed (0 to 99) | Q | Calendar quarter of the year (1 to 4) | MM | Month of the year (01 to 12) | ZMM | Month of the year with leading zeros
suppressed (1 to 12) | DD | Day of the month (01 to 31) | ZDD | Day of the month with leading zero suppressed
(1 to 31) | DDD | Day of the year (001 to 366). | ZDDD | DDD with leading zeros suppressed (1
to 366) | D | Day of the week (1 to 7 where Sunday
is 1, Monday is 2,...) | WW | Week of the year (01 to 53) | ZWW | Week of the year with leading zero suppressed
(1 to 53) | Mon | Month of the year in ASCII format (Jan,
Feb,...) | Day | Day of the week in ASCII format (Sun,
Mon,...) | MON | Month of the year in ASCII (uppercase)
format (JAN, FEB,...) | DAY | Day of the week in ASCII (uppercase)
format (SUN, MON,...) |
Table 9-7 Valid
Characters for Punctuation - | Hyphen | / | Slash | . | Dot | | Blank | , | Comma | | Null (or no delimiter) |
Thus, YYYY.MON.DAY, YY/MM/DD, DDMONYY,
and DD-ZMM-YYYY are valid date
formats. For example, "31 Jan 1997" when formatted
through DD-ZMM-YYYY results in
"31-1-1997," formatted through YYYY.MON.DAY results
in "1997.JAN.FRI," while YYYYMMDD
results in "19970131." | | | | | NOTE: Mixing the NULL punctuation character with other punctuation
characters is not allowed. Thus, YYYY/MM/DD
is a valid format, while YYYYMM/DD
is not. fmtdatelen parameter is length
of formatspec parameter including the
null termination character. | | | | |
Syntax I32V * CA CA I32 I32 I32V HPDATEFORMAT(datecode,inputdate,formatspec,fmtdate,fmtdatelen,status,cutoff)
|
Parameters - datecode
is a 32-bit signed integer by value. This value should be one of the date type codes listed in
the table, "Supported Date Formats." - inputdate
is the input date. The interpretation depends upon the value of datecode.
See the table, "Supported Date Formats," for the
supported datecodes and their layouts. - formatspec
is a character array (required). This should be a NULL terminated string as per the syntax
explained above in the table, "Format Specification Strings." - fmtdate
is a character array (required). This array size should be at least that of formatspec.
On return, it will contain the date formatted as per the formatspec. If an invalid date is passed, on return from the intrinsic
its contents will be UNKNOWN. For
the "HP Standard Formats," if special values in
the table, "Special Date Values," are passed for
date parameter, on return from the intrinsic, the value of the string
will be appropriately initialized. For example, for the date type
18, the initialized values for different special date values are
as follows: Date Value | Returned Contents |
---|
00000000 | "UNKNOWN" | 00000101 | "INVALID" | 00000102 | "NEVER" | 00000103 | "NEEDED" | 00000104 | "EXPIRED" | 00000105 | "ILLEGAL" |
If the character array passed does not have enough space to
hold the special values or the formatted date, the behavior is undefined. - fmtdatelen
is a 32 bit integer by reference (required). On input, it is the length of the formatspec
parameter. On return, it represents the number of characters HPDATEFORMAT
placed into fmtdate. - status
is the HPE_STATUS
parameter through which the error codes are returned. A value of
0 indicates no error and no warnings. - cutoff
is a 32-bit signed integer by value (optional). This is used in validating and converting from two-digit to
four-digit years. (See HPDATECONVERT
documentation for more information on the cutoff
parameter).
This intrinsic determines the number of days that separate
two given dates. Syntax I32V * * I32 I32 I32V HPDATEDIFF(datecode, firstdate,seconddate,diffindays,status,cutoff)
|
Parameters - datecode
is a 32-bit signed integer by value. This value should be one of the date type codes listed in
the table, "Supported Date Formats." - firstdate
is the first input date. The interpretation depends
upon the value of datecode. See the table,
"Supported Date Formats," for the supported datecodes
and their layouts. - seconddate
is the second input date. The interpretation depends
upon the value of datecode. See the table,
"Supported Date Formats," for the supported datecodes
and their layouts. - diffindays
is the number of days difference between the two
dates, computed as: seconddateminusfirstdate.
Thus, if seconddate is earlier than firstdate,
diffindays will be negative. - status
is the HPE_STATUS
parameter through which the error codes are returned. A value of
0 indicates no error and no warnings. - cutoff
is a 32-bit signed integer by value (optional). This is used in validating and converting the two-digit years
to four-digit years before computing the difference. (See HPDATECONVERT
documentation for more information on cutoff
parameter.)
This intrinsic adds or subtracts a specified offset to or
from the given date. Syntax I32V * I32V * I32 I32V HPDATEOFFSET(datecode,inputdate,offset,outputdate,status,cutoff)
|
Parameters - datecode
is a 32-bit signed integer by value This value should be one of the date type codes listed in
the table, "Supported Date Formats." - inputdate
is the input date. The interpretation depends upon
the value of datecode. See the table,
"Supported Date Formats," for the supported datecodes
and their layouts. - offset
is a 32-bit signed integer by value. The number of days to be added to the input date. A negative
value will result in a subtraction. - outputdate
is the output date. The result of the date offset
operation. The interpretation depends upon the value of datecode.
See the table, "Supported Date Formats," for the
supported datecodes and their layouts. - status
is the HPE_STATUS
parameter through which the error codes are returned. A value of
0 indicates no error and no warnings. - cutoff
is a 32-bit signed integer by value (optional). This is used in validating and converting the two-digit years
to four digit ones before computing the difference. (See HPDATECONVERT
documentation for more information.)
This intrinsic checks the validity of the given date with
respect to the supported formats given in the table, "Supported
Date Formats." Syntax I32 I32V * I32V result := HPDATEVALIDATE(datecode,inputdate,cutoff)
|
Parameters - datecode
is a 32-bit signed integer by value. This value should be one of the date type codes listed in
the table, "Supported Date Formats." - inputdate
is the input date. The interpretation depends upon the value of datecode.
See the table, "Supported Date Formats," for the
supported datecodes and their layouts. - cutoff
is a 32-bit signed integer by value (optional). This is used in validating dates with two digit years. (See
HPDATECONVERT
documentation for more information on cutoff
parameter). - result
is a 32-bit signed integer (assigned functional
return). This value will be 0 if the inputdate
conforms to the date format represented by datecode.
If it is not so, its value will be positive. If an error has occurred
in evaluating the conformance, its value will be negative. This
return value ranges from -999 to 1.
The new HPCALENDAR
intrinsic returns the date in the supported date type code 4 listed
in the table, "Supported Date Formats." (This
is also a HP standard format.) Syntax where date is the 32-bit unsigned
integer (assigned functional return). This returns the calendar date in the following format: Table 9-8 HPCALENDAR
Date Format Bits | Value/Meaning |
---|
23:9 | Day of year | 0:23 | Year since 1900 |
This a new routine to handle HPCALENDAR
format. It does the same job as FMTCALENDAR
except that it accepts the 32-bit integer returned by HPCALENDAR
intrinsic. Syntax I32V CA HPFMTCALENDAR(date,formatdate)
|
Parameters - date
is a 32-bit signed integer by value This holds the calendar date, in the same format as the HPCALENDAR
intrinsic (that is, date type 4). - formatdate
returns the formatted calendar date in a 17-character
array. If the day of the month is less than 10, a blank precedes
it. For example,
Following are two examples: The Pascal program example uses most
of the new date intrinsics. The COBOL program example uses the HPDATECONVERT
intrinsic.
Pascal Example of New Date Intrinsics $standard_level 'hp_modcal'$ Program dateintr(input,output); {Constants for the different date types.} const hp_dt_mpe_time_stamp_fmt = 1; hp_dt_packed_yymmdd_fmt = 2; hp_dt_packed_yyddd_fmt = 3; hp_dt_new_calendar_fmt = 4; hp_dt_posix_time_stamp_fmt = 10; hp_dt_calendar_fmt = 14; hp_dt_int_yymmdd_fmt = 15; hp_dt_int_mmddyy_fmt = 16; hp_dt_int_ddmmyy_fmt = 17; hp_dt_int_yyyymmdd_fmt = 18; hp_dt_ascii_yymmdd_fmt = 25; hp_dt_ascii_mmddyy_fmt = 26; hp_dt_ascii_ddmmyy_fmt = 27; hp_dt_mm3000_yymmdd_fmt = 35; hp_dt_mm3000_mmddyy_fmt = 36; hp_dt_mm3000_ddmmyy_fmt = 37; hp_dt_ascii_yyyymmdd_fmt = 38; {Type definitions for the program} type pac_20 = packed array [1..20] of char; iptr_type = ^integer; VAR date2_pac : pac_20; {Dates in packed character arrays.} fmt_pac : pac_20; print_pac : pac_20; cutoff : integer; {To represent cutoff date.} date1 : integer; {Working dates.} date1_18 : integer; date2_18 : integer; date3_18 : integer; i : integer; {temp variables.} inptype : integer; j : integer; outtype : integer; print_len : integer; {Length of formatted date.} temp_date : integer; {Another temp variable} status : integer; function HPCALENDAR : integer; intrinsic; procedure HPFMTCALENDAR; intrinsic; function HPDATEVALIDATE : integer; intrinsic; procedure HPDATEFORMAT ; intrinsic; procedure HPDATECONVERT ; intrinsic; procedure HPDATEOFFSET ; intrinsic; procedure HPDATEDIFF ; intrinsic;
|
begin {Initialize the variables.} cutoff := 50; inptype := hp_dt_int_ddmmyy_fmt; date2_pac := '960121'; {The YYMMDD date in Supported format '25'.} date1 := 230196; {The DDMMYY date in Supported format '17'.} {conversion from one non standard formatto another} HPDATECONVERT(inptype,date1,hp_dt_ascii_yymmdd_fmt,fmt_pac, status,cutoff); if( status <> 0) then writeln('HPDATECONVERT intrinsic returned error',status); {Convert 'date1' to the YYYYMMDD integer format. With 50} {as the cutoff year. } outtype := hp_dt_int_yyyymmdd_fmt; HPDATECONVERT(inptype,date1,outtype,date1_18,status,cutoff); if( status <> 0) then writeln('HPDATECONVERT intrinsic returned error',status); {Convert the 'date2_pac' to a YYMMDD integer format.} {Default cutoff is assumed (i.e., 50) } HPDATECONVERT(hp_dt_ascii_yymmdd_fmt,date2_pac, outtype,date2_18,status); if( status <> 0) then writeln('HPDATECONVERT intrinsic returned error',status); {compute the difference between the two dates} HPDATEDIFF(outtype, date1_18,date2_18,temp_date,status,cutoff); if( temp_date < 0) then writeln(date1,' is #',temp_date, 'days later compared to ',date2_pac) else if (temp_date > 0) then writeln(date2_pac,' is #',temp_date, 'days later compared to ',date1) else writeln(date1,' is same as ',date2_pac); {offset date1_18 by the difference to get the } {value of date2_18 through HPDATEOFFSET intrinsic.} HPDATEOFFSET(outtype,date1_18,temp_date,date3_18,status,cutoff); if( (date3_18 <> date2_18 ) and (status = 0)) then writeln('Error Malfunction of HPDATEOFFSET intrinsic'); {Use the flexibility in converting the date to a display } {string. Use '#0' to NULL terminate the format } {specification string. } fmt_pac := 'YY.ZMM.ZDD'#0; print_len := 11; { 11 characters including #0 in fmt_pac } HPDATEFORMAT(outtype,date1_18,fmt_pac,print_pac,print_len,status);
|
if( status <> 0) then writeln('HPDATEFORMAT intrinsic returned error',status); writeln('The converted date is: ',print_pac); {The following demonstrates how a byte array can be } {passed in place of an integer. We are storing the } {integer 230196 in a packed array of characters, which is} {an equivalent of a byte array. We subsequently cast the } {address of this array to an integer pointer to read the } {integer value out of it. } HPDATECONVERT(hp_dt_int_yyyymmdd_fmt,date1_18, hp_dt_int_ddmmyy_fmt,fmt_pac,status); $push, type_coercion 'storage'$ if( iptr_type (addr(fmt_pac))^ = date1 ) then writeln( 'Program worked fine! ') else writeln( 'Error, in using byte array parameters !'); $pop$ end.
|
The expected output from the program is: 230196 is # 2days later compared to 960121 The converted date is : 96.1.23 Program worked fine!
|
COBOL Example of HPDATECONVERT IDENTIFICATION DIVISION. PROGRAM-ID. DATEINTR. REMARKS. SAMPLE PROGRAM USING DATE INTRINSICS DATA DIVISION. WORKING-STORAGE SECTION. *Date code for YYMMDD is 25, for YYYYMMDD is 38 01 INDATE-CODE PIC S9(9) VALUE 25. 01 OUTDATE-CODE PIC S9(9) VALUE 38. 01 SPLITYEAR PIC S9(9) VALUE 70. 01 OUTDATE-YYYYMMDD PIC X(8) VALUE SPACES. 01 INDATE-YYMMDD PIC X(6) VALUE SPACES. 01 STATUS-VAR. 05 S-INFO PIC S9(4) COMP VALUE 0. 05 S-SUBSYS PIC S9(4) COMP VALUE 0. PROCEDURE DIVISION. CONVERT-DATE-PARA. DISPLAY 'Enter the date in YYMMDD format:' ACCEPT INDATE-YYMMDD CALL INTRINSIC "HPDATECONVERT" USING INDATE-CODE INDATE-YYMMDD OUTDATE-CODE OUTDATE-YYYYMMDD STATUS-VAR SPLITYEAR IF S-INFO NOT = 0 PERFORM DISPLAY-ERROR ELSE DISPLAY "Convert Date in YYYYMMDD = " OUTDATE-YYYYMMDD END-IF STOP RUN. DISPLAY-ERROR. DISPLAY "HPDATECONVERT FAILED. ERROR = " S-INFO.
|
|