/* Vmstime.c v1.6A Author: Paul Nankervis 1.4 Changed declarations NOT to define DOLLAR identifiers unless DOLLAR is defined (some compilers can't handle $'s!) 1.4A Changed default DOLLAR handling to include DOLLAR identifers unless NO_DOLLAR is defined (ie #ifdef DOLLAR to #ifndef NO_DOLLAR) 1.5 Added 64 bit support and cvt_internal routines 1.6 Change addx, subx and compare to use larger integers 1.6A Fixed endian problems in addx/subx Please send bug reports or requests for enhancement or improvement via email to: PaulNank@au1.ibm.com This module contains versions of the VMS time routines sys$numtim(), sys$asctim() and friends... They are intended to be compatible with the routines of the same name on a VMS system (so descriptors feature regularly!) This code relies on being able to manipluate day numbers and times using 32 bit arithmetic to crack a VMS quadword byte by byte. If your C compiler doesn't have 32 bit unsigned integer types then give up now! On a 64 bit systems VMSTIME_64BIT can be defined to do 64 bit operations directly.... One advantage of doing arihmetic byte by byte is that the code does not depend on what 'endian' the target machine is - it will always treat bytes in the same order! (Hopefully VMS time bytes will always be in the same order!) Note: VMS time quadwords are simply an eight byte integer (quadword) representing the number of 100 nanasecond units since 17-Nov-1858. Delta times (time differences) are represented by a negative quadword value. It is interesting that Windows UTC times are in the same units but are based on the year 1601. A couple of stupid questions to go on with:- o OK, I give up! What is the difference between a zero date and a zero delta time? o Anyone notice that the use of 16 bit words in sys$numtim restricts delta times to 65535 days? Paul Nankervis paulnank@au1.ibm.com Note: The routine are defined here with an underscore instead of a dollar symbol (ie sys_asctim instead of sys$asctim). This avoids problems on systems which don't handle the '$' well, and it avoids conflicts under VMS. To call these routines from an application which uses normal 'dollar' names simply include the header file "vmstime.h" which will remap the names unless NO_DOLLAR is defined first! (ie define sys$asctim as sys_asctim). */ #include #include #include #include #ifdef _WIN32 #include /* Use windows routines to get currrent time */ #else #ifndef NO_LOCALTIME #if defined(VMS) && defined(__GNUC__) #include /* For GCC include libraries on VMS (sigh!) */ #else #include /* For ftime() */ #endif #endif #endif #include "vmstime.h" /* Our header file! */ #define TIMEBASE 100000 /* 10 millisecond units in quadword */ #define TIMESIZE 8640000 /* Factor between dates & times */ #define QUAD_CENTURY_DAYS 146097 /* (400*365) + (400/4) - (400/100) + (400/400) */ #define CENTURY_DAYS 36524 /* (100*365) + (100/4) - (100/100) */ #define QUAD_YEAR_DAYS 1461 /* (4*365) + (4/4) */ #define YEAR_DAYS 365 /* 365 */ #define OFFSET_DAYS 94187 /* ((1858-1601)*365) + ((1858-1601)/4) - ((1858-1601)/100) + ((1858-1601)/400) + 320 OFFSET FROM 1/1/1601 TO 17/11/1858 */ #define BASE_YEAR 1601 /* lib$addx & lib$subx perform arithmetic using a small integer at a time. Compare can be done using a full size integer (if the endian is correct.Note that on a big endian machine the maximum unit of work is always one character!!! */ #ifdef VMSTIME_64BIT #define LARGE_INT unsigned VMSTIME_64BIT #define SMALL_INT unsigned int #define WORK_INT unsigned VMSTIME_64BIT #else #define WORK_INT unsigned int #if defined(VMS) || defined(_WIN32) #define LARGE_INT unsigned int #define SMALL_INT unsigned short #else #define SMALL_INT unsigned char #endif #endif unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd) { register int count; if (lenadd == NULL) { count = 8; } else { count = *lenadd * 4; } #ifdef LARGE_INT if (count == sizeof(LARGE_INT)) { *(LARGE_INT *) result = *(LARGE_INT *) addant + *(LARGE_INT *) addee; } else { #else { #endif register SMALL_INT *ant = (SMALL_INT *) addant; register SMALL_INT *ee = (SMALL_INT *) addee; register SMALL_INT *res = (SMALL_INT *) result; register WORK_INT carry = 0; count /= sizeof(SMALL_INT); do { carry = *ant++ + (carry + *ee++); *res++ = carry; carry = carry >> (sizeof(SMALL_INT) * 8); } while (--count > 0); } return LIB__NORMAL; } unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd) { register int count; if (lenadd == NULL) { count = 8; } else { count = *lenadd * 4; } #ifdef LARGE_INT if (count == sizeof(LARGE_INT)) { *(LARGE_INT *) result = *(LARGE_INT *) subant + *(LARGE_INT *) subee; } else { #else { #endif register SMALL_INT *ant = (SMALL_INT *) subant; register SMALL_INT *ee = (SMALL_INT *) subee; register SMALL_INT *res = (SMALL_INT *) result; register WORK_INT carry = 0; count /= sizeof(SMALL_INT); do { carry = *ant++ - (carry + *ee++); *res++ = carry; carry = (carry >> (sizeof(SMALL_INT) * 8)) & 1; } while (--count > 0); } return LIB__NORMAL; } /* vmstime_compare() is used to compare times. returns -1 if time2 is bigger 0 if times are equal 1 if time1 is bigger */ int vmstime_compare(VMSTIME time1,VMSTIME time2) { #ifdef VMSTIME_64BIT if (*time1 > *time2) return 1; if (*time1 < *time2) return -1; #else #ifdef LARGE_INT register int count = 8 / sizeof(LARGE_INT); register LARGE_INT *t1 = (LARGE_INT *) time1 + 8 / sizeof(LARGE_INT) - 1; register LARGE_INT *t2 = (LARGE_INT *) time2 + 8 / sizeof(LARGE_INT) - 1; #else register int count = 8 / sizeof(SMALL_INT); register SMALL_INT *t1 = (SMALL_INT *) time1 + 8 / sizeof(SMALL_INT) - 1; register SMALL_INT *t2 = (SMALL_INT *) time2 + 8 / sizeof(SMALL_INT) - 1; #endif do { if (*t1 > *t2) return 1; if (*t1 < *t2) return -1; t1--; t2--; } while (--count > 0); #endif return 0; } /* vmstime_date_time() is an internal routine assemble the date (day number) and time in a time quadword - basically the opposite of lib_day() */ unsigned vmstime_date_time(int days,VMSTIME timadr,int day_time) { /* Put date/time into VMS quadword timbuf... */ #ifdef VMSTIME_64BIT if (day_time <= -TIMESIZE || day_time >= TIMESIZE) return SS__IVTIME; *timadr = ((days * (VMSTIME_64BIT) TIMESIZE) + day_time) * TIMEBASE; #else register unsigned time = day_time; register unsigned char *dstptr = timadr; register int count = 8,carry = 0,date = days; if (day_time <= -TIMESIZE || day_time >= TIMESIZE) return SS__IVTIME; if (date == 0 && day_time < 0) { do { carry += (time & 0xFF) * TIMEBASE; time = (time >> 8) | 0xFF000000; *dstptr++ = carry; carry = (carry >> 8); } while (--count > 0); } else{ do { time += (date & 0xFF) * TIMESIZE; date = (date >> 8); carry += (time & 0xFF) * TIMEBASE; time = (time >> 8); *dstptr++ = carry; carry = (carry >> 8); } while (--count > 0); } #endif return SS__NORMAL; } /* lib_cvt_vectim() takes individual date/time fields from a seven word buffer and munges them into a time quadword... */ int vmstime_mthend[] = {0,31,60,91,121,152,182,213,244,274,305,335,366}; unsigned lib_cvt_vectim(unsigned short timvec[7],VMSTIME timadr) { register unsigned sts; register int year,month,days; /* lib_cvt_vectim packs the seven date/time components into a quadword... */ if (timvec[3] > 23 || timvec[4] > 59 || timvec[5] > 59 || timvec[6] > 99) return SS__IVTIME; year = timvec[0]; month = timvec[1]; days = timvec[2]; if (year == 0 && month == 0) { /* Pass back delta result */ sts = vmstime_date_time(-days,timadr,timvec[3] * -360000 - timvec[4] * 6000 - timvec[5] * 100 - timvec[6]); } else { /* Generate days since base date.. */ int nonleap_adjust = 0; if (year < 1858 || year > 9999 || month < 1 || month > 12 || days < 1) return SS__IVTIME; days += vmstime_mthend[month - 1]; if (month > 1) { if (year % 4) { nonleap_adjust = 1; } else { if ((year % 100) == 0 && year % 400) nonleap_adjust = 1; } } if (days > vmstime_mthend[month] || (month == 2 && days > vmstime_mthend[month] - nonleap_adjust)) return SS__IVTIME; if (month > 2) days -= nonleap_adjust; year -= BASE_YEAR; days += year * YEAR_DAYS + year / 4 - year / 100 + year / 400 - OFFSET_DAYS - 1; sts = vmstime_date_time(days,timadr,timvec[3] * 360000 + timvec[4] * 6000 + timvec[5] * 100 + timvec[6]); } return sts; } /* sys_gettim() implemented here by getting C library time in seconds since 1-Jan-1970 and munging into a time quadword... Can use time() to just get seconds or ftime() to find seconds with milli-seconds. localtime() is used to find non-offset time. Note that some libraries don't do any of this particularly well! Under windows we can use a munged version of the internal UTC time */ unsigned sys_gettim(VMSTIME timadr) { #ifdef _WIN32 /* Get windows time adjust for timezone and convert to VMS... */ GetSystemTimeAsFileTime((struct _FILETIME *)timadr); FileTimeToLocalFileTime((struct _FILETIME *)timadr,(struct _FILETIME *)timadr); return vmstime_from_nt(timadr,timadr); #else #ifdef NO_LOCALTIME /* Use time straight from time() */ time_t curtim = time(NULL); return vmstime_date_time(40587 + curtim / 86400,timadr, (curtim % 86400) * 100); #else /* Get time from ftime() and localtime() */ struct timeb timval; struct tm *lclptr; unsigned short timvec[7]; timval.millitm = 0; /* for broken versions of ftime() */ ftime(&timval); lclptr = localtime(&timval.time); timvec[0] = lclptr->tm_year + 1900; timvec[1] = lclptr->tm_mon + 1; timvec[2] = lclptr->tm_mday; timvec[3] = lclptr->tm_hour; timvec[4] = lclptr->tm_min; timvec[5] = lclptr->tm_sec; timvec[6] = timval.millitm / 10; return lib_cvt_vectim(timvec,timadr); #endif #endif } /* vmstime_day() is a routine to crack time quadwords into a day number and time. It is different to lib_day() in that delta times are returned as negative values to distinguish small delta values from dates */ unsigned vmstime_day(int *days,VMSTIME timadr,int *day_time) { VMSTIME wrktim; #ifdef VMSTIME_64BIT register VMSTIME_64BIT timval; #else register int delta = 0; register unsigned char *srcptr; #endif /* If no time specified get current using gettim() */ if (timadr == NULL) { register unsigned sts; sts = sys_gettim(wrktim); if (!(sts & 1)) return sts; #ifdef VMSTIME_64BIT timval = *wrktim; } else { timval = *timadr; } timval /= TIMEBASE; *days = (timval / TIMESIZE); if (day_time != NULL) *day_time = (timval % TIMESIZE); #else srcptr = wrktim + 7; } else { /* Check specified time for delta... */ if ((delta = ISDELTA(timadr))) { /* We have to 2's complement delta times - sigh!! */ register int count = 8,carry = 1; register unsigned char *dstptr = wrktim; srcptr = timadr; do { carry += (~*srcptr++) & 0xFF; *dstptr++ = carry; carry = carry >> 8; } while (--count > 0); srcptr = wrktim + 7; } else { srcptr = timadr + 7; } } /* Extract the date and time from the quadword... */ { register int count = 5,date = 0; register unsigned time = 0, carry; carry = *srcptr--; carry = (carry << 8) | *srcptr--; carry = (carry << 8) | *srcptr--; do { carry = (carry << 8) | *srcptr--; time = (time << 8) | (carry / TIMEBASE); date = (date << 8) | (time / TIMESIZE); carry %= TIMEBASE; time %= TIMESIZE; } while (--count > 0); /* Return results... */ if (delta) { *days = -(int) date; if (day_time != NULL) *day_time = -(int) time; } else { *days = date; if (day_time != NULL) *day_time = time; } } #endif return LIB__NORMAL; } /* lib_day() is a routine to crack time quadwords into a day number and time. */ unsigned lib_day(int *days,VMSTIME timadr,int *day_time) { register unsigned sts; sts = vmstime_day(days,timadr,day_time); if (*day_time < 0) *day_time = -*day_time; return sts; } /* vmstime_numtim() takes a time quadword and breaks it into a seven word time vector (year,month,day,hour...) */ unsigned vmstime_numtim(unsigned short timvec[7],VMSTIME timadr, int *days,int *day_time,int *day_of_year) { register int date,time; /* Use vmstime_day to crack time into days/time... */ { register unsigned sts; sts = vmstime_day(days,timadr,day_time); if (!(sts & 1)) return sts; date = *days; time = *day_time; } /* Delta time or date? */ if (date < 0 || time < 0) { timvec[0] = 0; /* Year */ timvec[1] = 0; /* Month */ timvec[2] = -date; /* Days */ time = -time; } else { /* Date - calculate years to quad century... */ register int year; date += OFFSET_DAYS; year = BASE_YEAR + (date / QUAD_CENTURY_DAYS) * 400; date %= QUAD_CENTURY_DAYS; /* Add years to century - last century in quad is longer!! */ { register int century = date / CENTURY_DAYS; if (century == 4) century = 3; if (century) { year += century * 100; date -= century * CENTURY_DAYS; } } /* Add years to quad year... */ year += (date / QUAD_YEAR_DAYS) * 4; date %= QUAD_YEAR_DAYS; /* Finally to current year - last year in quad is longer!! */ { register int yearno = date / YEAR_DAYS; if (yearno == 4) yearno = 3; if (yearno) { year += yearno; date -= yearno * YEAR_DAYS; } } if (day_of_year != NULL) *day_of_year = date; /* Non-leap adjustment for years which have no Feb 29th */ if (date++ > 58) { if (year % 4) { date++; } else { if ((year % 100) == 0 && year % 400) date++; } } /* Figure out month and return results... */ { register int month = 1; while (date > vmstime_mthend[month]) month++; timvec[0] = year; /* Year */ timvec[1] = month; /* Month */ timvec[2] = date - vmstime_mthend[month - 1]; /* Days */ } } /* Return time information... */ timvec[6] = time % 100; /* Hundredths */ time /= 100; timvec[5] = time % 60; /* Seconds */ time /= 60; timvec[4] = time % 60; /* Minutes */ timvec[3] = time / 60; /* Hours */ return SS__NORMAL; } /* sys_numtim() takes a time quadword and breaks it into a seven word time vector (year,month,day,hour...) */ unsigned sys_numtim(unsigned short timvec[7],VMSTIME timadr) { int days,day_time; return vmstime_numtim(timvec,timadr,&days,&day_time,NULL); } /* Define internal tables... */ char vmstime_punct[] = "::."; char vmstime_digits[] = "0123456789"; char vmstime_months[] = "-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-"; /* vmstime_getnum() internal routine to convert a printable number to binary */ char *vmstime_getnum(char *ptr,char *end,unsigned short *result,int *scale) { register int numval = 0; register int scaleval = 1; register char *chrptr = ptr; do { register int binval = 0; register char digit = *chrptr++; do { if (digit == vmstime_digits[binval]) break; } while (++binval < 10); numval = numval * 10 + binval; scaleval *= 10; } while (chrptr < end && isdigit(*chrptr)); *result = numval; *scale = scaleval; return chrptr; } #define NOVALUE 0xFFFF /* sys_bintim() takes a printable time and converts it to a time quadword */ unsigned sys_bintim(struct dsc_descriptor *timbuf,VMSTIME timadr) { int scale; unsigned short wrktim[7]; register int field_count = 0; register char *chrptr = timbuf->dsc_a_pointer; register char *endptr = chrptr + timbuf->dsc_w_length; /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* Get the day number or delta days... */ if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[2],&scale); field_count++; } else { wrktim[2] = NOVALUE; } /* Check for month separator "-" - if found then we have a date! */ if (chrptr < endptr && *chrptr == '-') { chrptr++; wrktim[0] = wrktim[1] = NOVALUE; wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = NOVALUE; /* See if there is a month... */ if (chrptr + 2 < endptr && *chrptr != '-') { register int month = 1; register char upmth0 = toupper(chrptr[0]); register char upmth1 = toupper(chrptr[1]); register char upmth2 = toupper(chrptr[2]); register char *mthptr = vmstime_months + 1; do { if (upmth0 == mthptr[0] && upmth1 == mthptr[1] && upmth2 == mthptr[2]) break; mthptr += 4; } while (++month <= 12); chrptr += 3; wrktim[1] = month; field_count++; } /* Now look for year... */ if (chrptr < endptr && *chrptr == '-') { chrptr++; if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[0],&scale); field_count++; } } } else { /* Set default values for delta time... */ wrktim[0] = wrktim[1] = 0; wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = 0; if (wrktim[2] == NOVALUE) wrktim[2] = 0; /* If no space then just a time value? */ if (chrptr < endptr && *chrptr != ' ') { wrktim[3] = wrktim[2]; wrktim[2] = 0; } field_count = 7; /* Don't use current time! */ } /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* Extract time fields... Note: we don't round hundredths into seconds */ { register int time_field; for (time_field = 0; time_field < 4 && chrptr < endptr; time_field++) { if (chrptr < endptr && isdigit(*chrptr)) { chrptr = vmstime_getnum(chrptr,endptr,&wrktim[time_field + 3],&scale); field_count++; if (time_field == 3) { register unsigned hundredth = wrktim[6] * 1000 / scale; if (hundredth < 995) hundredth += 5; wrktim[6] = hundredth / 10; break; } } if (chrptr < endptr && time_field < 3 && *chrptr == vmstime_punct[time_field]) chrptr++; } } /* Skip any spaces... */ while (chrptr < endptr && *chrptr == ' ') chrptr++; /* If anything left then we have a problem... */ if (chrptr < endptr) return SS__IVTIME; /* If some fields not specified use current time...*/ if (field_count < 7) { register int field; unsigned short curtim[7]; register unsigned sts = sys_numtim(curtim,NULL); if (!(sts & 1)) return sts; for (field = 0; field < 7; field++) { if (wrktim[field] == NOVALUE) wrktim[field] = curtim[field]; } } return lib_cvt_vectim(wrktim,timadr); } /* sys_asctim() converts a time quadword into printable form... */ unsigned sys_asctim(unsigned short *timlen,struct dsc_descriptor *timbuf, VMSTIME timadr,unsigned cvtflg) { unsigned short timvec[7]; register int count,timval; register char *chrptr = timbuf->dsc_a_pointer; register char *endptr = chrptr + timbuf->dsc_w_length; /* First use sys_numtim to get the date/time fields... */ { register unsigned sts; sts = sys_numtim(timvec,timadr); if (!(sts & 1)) return sts; } /* See if we want delta days or date... */ if (cvtflg == 0) { /* Check if date or delta time... */ if (timvec[0]) { /* Generate two digit day... */ if (chrptr < endptr) { if ((timval = timvec[2]) / 10 == 0) { *chrptr++ = ' '; } else { *chrptr++ = vmstime_digits[timval / 10]; } } if (chrptr < endptr) { *chrptr++ = vmstime_digits[timval % 10]; } /* Add month name with hyphen separators... */ if ((count = (endptr - chrptr)) > 5) count = 5; memcpy(chrptr,vmstime_months + ((timvec[1] - 1) * 4),count); chrptr += count; /* Get year... */ timval = timvec[0]; } else { /* Get delta days... */ timval = timvec[2]; } /* Common code for year number and delta days! Spaces first... */ count = 1000; if (timval < count && chrptr < endptr) { do { *chrptr++ = ' '; count /= 10; } while (timval < count && count > 1 && chrptr < endptr); } else { if (timval >= 10000) count = 10000; } /* Then digits... */ if (chrptr < endptr) { do { *chrptr++ = vmstime_digits[timval / count]; timval = timval % count; count /= 10; } while (count > 0 && chrptr < endptr); } /* Put a space between date and time... */ if (chrptr < endptr) *chrptr++ = ' '; } /* Move onto time fields... hh:mm:ss.hh */ if (chrptr < endptr) { count = 0; do { timval = timvec[count + 3]; *chrptr++ = vmstime_digits[timval / 10]; if (chrptr >= endptr) break; *chrptr++ = vmstime_digits[timval % 10]; if (count >= 3 || chrptr >= endptr) break; *chrptr++ = vmstime_punct[count++]; } while (chrptr < endptr); } /* We've done it - return length... */ if (timlen != NULL) *timlen = (chrptr - (char *) timbuf->dsc_a_pointer); return SS__NORMAL; } /* lib_day_of_week() computes day of week from time quadword... */ unsigned lib_day_of_week(VMSTIME timadr,unsigned *weekday) { int days; register unsigned sts; /* Use lib_day to crack quadword... */ sts = lib_day(&days,timadr,NULL); if (sts & 1) { *weekday = ((days + 2) % 7) + 1; } return sts; } /* lib_mult_delta_time multiplies a delta time by a scalar integer... */ unsigned lib_mult_delta_time(int *multiple,VMSTIME timadr) { register int factor = *multiple; /* Check for delta time... */ if (!ISDELTA(timadr)) return SS__IVTIME; /* Use absolute factor... */ if (factor < 0) factor = -factor; #ifdef VMSTIME_64BIT *timadr *= factor; #else { register int count = 8; register unsigned carry = 0; register unsigned char *ptr = timadr; do { carry += *ptr * factor; *ptr++ = carry; carry = (carry >> 8); } while (--count > 0); } #endif return LIB__NORMAL; } /* lib_add_times() adds two quadword time values */ unsigned lib_add_times(VMSTIME time1,VMSTIME time2,VMSTIME result) { if (ISDELTA(time1)) { if (ISDELTA(time2)) { #ifdef VMSTIME_64BIT *result = *time1 + *time2; } else { *result = *time2 - *time1; #else lib_addx(time1,time2,result,NULL); } else { lib_subx(time2,time1,result,NULL); #endif } } else { if (ISDELTA(time2)) { #ifdef VMSTIME_64BIT *result = *time1 - *time2; #else lib_subx(time1,time2,result,NULL); #endif } else { return LIB__ONEDELTIM; } } return LIB__NORMAL; } /* lib_sub_times() subtracts two quadword time values */ unsigned lib_sub_times(VMSTIME time1,VMSTIME time2,VMSTIME result) { #ifdef VMSTIME_64BIT if (ISDELTA(time1) != ISDELTA(time2)) { *result = *time1 + *time2; } else { if (*time1 < *time2) { *result = *time1 - *time2; } else { *result = *time2 - *time1; } } #else if (ISDELTA(time1) != ISDELTA(time2)) { lib_addx(time1,time2,result,NULL); } else { if (vmstime_compare(time1,time2) < 0) { lib_subx(time1,time2,result,NULL); } else { lib_subx(time2,time1,result,NULL); } } #endif return LIB__NORMAL; } /* lib_cvt_from_internal_time() extracts a time field from a time value */ unsigned lib_cvt_from_internal_time(unsigned *operation, unsigned *result,VMSTIME input_time) { register unsigned resval; unsigned short timvec[7]; int days,day_time,day_of_year; if (*operation >= LIB$K_MAX_OPERATION) return LIB__INVOPER; { register unsigned sts; sts = vmstime_numtim(timvec,input_time,&days,&day_time,&day_of_year); if (!(sts & 1)) return sts; } if (timvec[0] != 0) { switch (*operation) { case LIB$K_MONTH_OF_YEAR: resval = timvec[1]; break; case LIB$K_DAY_OF_YEAR: resval = day_of_year + 1; break; case LIB$K_HOUR_OF_YEAR: resval = day_of_year * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_YEAR: resval = (day_of_year * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_YEAR: resval = ((day_of_year * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_DAY_OF_MONTH: resval = timvec[2]; break; case LIB$K_HOUR_OF_MONTH: resval = (timvec[2] - 1) * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_MONTH: resval = ((timvec[2] - 1) * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_MONTH: resval = (((timvec[2] - 1) * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_DAY_OF_WEEK: resval = ((days + 2) % 7) + 1; break; case LIB$K_HOUR_OF_WEEK: resval = ((days + 2) % 7) * 24 + timvec[3]; break; case LIB$K_MINUTE_OF_WEEK: resval = (((days + 2) % 7) * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_SECOND_OF_WEEK: resval = ((((days + 2) % 7) * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_HOUR_OF_DAY: resval = timvec[3]; break; case LIB$K_MINUTE_OF_DAY: resval = timvec[3] * 60 + timvec[4]; break; case LIB$K_SECOND_OF_DAY: resval = (timvec[3] * 60 + timvec[4]) * 60 + timvec[5]; break; case LIB$K_MINUTE_OF_HOUR: resval = timvec[4]; break; case LIB$K_SECOND_OF_HOUR: resval = timvec[4] * 60 + timvec[5]; break; case LIB$K_SECOND_OF_MINUTE: resval = timvec[5]; break; case LIB$K_JULIAN_DATE: resval = days; break; default: return LIB__DELTIMREQ; } } else { switch (*operation) { case LIB$K_DELTA_WEEKS: resval = timvec[2] / 7; break; case LIB$K_DELTA_DAYS: resval = timvec[2]; break; case LIB$K_DELTA_HOURS: resval = timvec[2] * 24 + timvec[3]; break; case LIB$K_DELTA_MINUTES: resval = (timvec[2] * 24 + timvec[3]) * 60 + timvec[4]; break; case LIB$K_DELTA_SECONDS: resval = ((timvec[2] * 24 + timvec[3]) * 60 + timvec[4]) * 60 + timvec[5]; break; case 0: case LIB$K_DELTA_WEEKS_F: case LIB$K_DELTA_DAYS_F: case LIB$K_DELTA_HOURS_F: case LIB$K_DELTA_MINUTES_F: case LIB$K_DELTA_SECONDS_F: return LIB__INVOPER; default: return LIB__ABSTIMREQ; } } *result = resval; return LIB__NORMAL; } unsigned char vmstime_oneweek[] = {0x00,0xc0,0x1b,0xd7,0x7f,0xfa,0xff,0xff}; unsigned char vmstime_oneday[] = {0x00,0x40,0x96,0xd5,0x36,0xff,0xff,0xff}; unsigned char vmstime_onehour[] = {0x00,0x98,0x3b,0x9e,0xf7,0xff,0xff,0xff}; unsigned char vmstime_oneminute[] = {0x00,0xba,0x3c,0xdc,0xff,0xff,0xff,0xff}; unsigned char vmstime_onesecond[] = {0x80,0x69,0x67,0xff,0xff,0xff,0xff,0xff}; /* lib_cvt_to_internal_time() converts a time field to a time value */ unsigned lib_cvt_to_internal_time(unsigned *operation,int *input, VMSTIME result) { unsigned char *ptr; if (*input < 1) return LIB__IVTIME; switch (*operation) { case LIB$K_DELTA_WEEKS: ptr = vmstime_oneweek; break; case LIB$K_DELTA_DAYS: ptr = vmstime_oneday; break; case LIB$K_DELTA_HOURS: ptr = vmstime_onehour; break; case LIB$K_DELTA_MINUTES: ptr = vmstime_oneminute; break; case LIB$K_DELTA_SECONDS: ptr = vmstime_onesecond; break; default: return LIB__INVOPER; } memcpy(result,ptr,sizeof(VMSTIME)); return lib_mult_delta_time(input,result); } /* Difference between VMS and NT is 94187 days.... */ unsigned char vmstime_nt_offset[] = {0x00,0xc0,0xac,0x76,0x88,0xe3,0xde,0xfe}; /* vmstime_from_nt() convert Windows NT time to vmstime */ unsigned vmstime_from_nt(VMSTIME nt_time,VMSTIME vms_time) { if (ISDELTA(nt_time)) return LIB__IVTIME; return lib_sub_times(nt_time,(pVMSTIME) vmstime_nt_offset,vms_time); } /* vmstime_to_nt() convert vmstime to Windows NT time */ unsigned vmstime_to_nt(VMSTIME vms_time,VMSTIME nt_time) { if (ISDELTA(vms_time)) return LIB__IVTIME; return lib_add_times(vms_time,(pVMSTIME) vmstime_nt_offset,nt_time); }