IBM Metal C

Examples

Example 3. Date Routines

While working with the creation and last referral dates of MVS data sets (non VSAM) obtained from their VTOC entries, I needed a routine to convert the dates to other formats. Converting the dates first to Julian day number was the solution I decided upon. Programmers (myself included) often refer to dates in the form yyyy.ddd as Julian dates, but this is not correct. Julian dates (abbreviated JD) are a continuous count of days and fractions since noon Universal Time on January 1, 4713 BCE. A Julian date is expressed as a real number; the number of whole days and fractions of a day from the base date. For example, the Julian date for CE 2014 October 24 02:30:00.0 UT is JD 2456954.604167.

The advantages to using a JDN for date routines is obvious. Two determine the difference between two dates, find the JDN of both dates and subtract. To advance a date, n number of days, add n to the JDN. To find the day of the week, calculate JDN modulo 7, etc.

The routines used here return integer results, so the JDN, as used here, starts at 00:00:00 on January 1, -4712, which is day 0. Day one is January 2, -4712, January 1, 2013 is 2,456,293, etc.

To obtain the current date/time getDate() can be used:

int getDate(struct dateTime *_dateTime);

This routine retrieves the TOD value from a store clock fast call and adjusts the time according to the value found in the cvt fields cvttz and cvtlso. These two fields adjust the UTC time returned by the stckf for time zone and leap second differences.

Passed to the routine is the struct dateTime, where the retrieved date/time information is stored and passed back to the calling routine.

struct dateTime                                                        
{                                                                      
    int  jdn;               // Julian Day Number                       
    int  Lilian;            // Lilian Date used by LE                  
    char yyyymmdd[9];       // e.g. 20141104                           
    char yyyymmdd2[11];     // e.g. 2014/11/04                         
    int  dayOfWeek;         // 0 - 6                                   
    char weekdayLong[9];    // Full text, e.g. "Monday"                
    char weekdayShort[4];   // Abbrev. Text, e.g. "Mon"                
    char time24[9];         // 24 hour hh:mm:ss                        
    char time12[9];         // 12 hour hh:mm:ss                        
    char ampm[3];           // AM or PM                                
    char monthLong[10];     // Full Text e.g. "January"                
    char monthShort[4];     // Abbrev. Month e.g. "Jan"                
    char yyyyddd[9];        // yyyy.ddd                                
    char longDate[40];      // Tuesday, November 04, 2014 10:54:38AM   
    // Binary Representation of Fields                                 
    short int dayOfYear;    // 1 - 366                                 
    short int year;                                                    
    short int month;                                                   
    short int day;                                                     
    short int hour;                                                    
    short int min;                                                     
    short int sec;                                                     
};                    

For date conversion purposes I created 12 routines.

Type Signatures

extern int ISODayToJulianDN(int year, int day);
extern int UnixTime(int JD);
extern int LilianDate(int JD);
extern int GregorianToJDN(int year, int month, int day);
extern void JulianDNToGregorian(int JD, int *year, int *month, int *day);
extern int dayOfTheYEAR(int year, int month, int day);
extern void dayOfYearToCalendar(int year, int *month, int *day);
extern int dayOfTheWeek(int JD);
extern int ISODayOfTheWeek(int JD);
extern int ANSIDate(int JD);
extern int TODToJDN(unsigned long long int TOD);
extern int isYearLeapYear(int year);

These routines facilitate the conversion from one date format to another. Included are yyyy.ddd (ISO date format), Unix time, and Lilian date which began at the start of the Gregorian Calendar on October 15, 1582. Lilian date is the format used by Language Environment®.

Most of the algorithms for this routines are from Jean Meeus, Astronomical Algorithms (Richmod, Virginia: Willmann-Bell, 1991) modified for my needs. I tested the routines on a Linux system using the NetBeans IDE (Oracle open source). They were then FTP'ed to MVS and the HLASM code generated using METAL C.

Performance testing of the GregorianToJDN routine with a date of 2014/10/28 executed 10,000,000 times took 4.12 CPU seconds or about 0.412μ seconds per call, on a zEnterprise 114 3.8GHz processor.

The C source code for all the routines appears below:

References

  1. Julian day, Wikipedia, 2014
  2. Jean Meeus, Astronomical Algorithms (Richmod, Virginia: Willmann-Bell, 1991)
  3. z/OS Metal C Programming Guide and Reference
  4. z/OS XL C/C++ Language Reference
  5. z/OS MVS Data Areas Volume 1