/*****************************************************************************/ /* SISCO SOFTWARE MODULE HEADER **********************************************/ /*****************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 2005 All Rights Reserved */ /* */ /* MODULE NAME : StdTimeW32.h */ /* PRODUCT(S) : Standard Time Management Library */ /* */ /* MODULE DESCRIPTION: */ /* Implementation of Standard Time Management Library Win32 Compatibility */ /* Layer. This module is compiled with STDTIMEW32_ENABLED on Windows to */ /* generate debugging code or to run emulation on Unix. To run on */ /* Windows, compile with STDTIMEW32_DISABLED. STDTIMEW32_ENABLED is */ /* required on Unix/Linux (that is, non-Windows) platforms. */ /* */ /* MODIFICATION LOG: */ /* Date Who Rev Comments */ /* -------- --- --- ----------------------------------------------------- */ /* 05/16/08 JRB 07 Fix DST adjustment in StdTimeW32LocalFileTimeToFileTime*/ /* 04/08/08 JRB 06 Chg FILETIME to portable STDTIME_WIN_FILETIME. */ /* 02/20/08 JRB 05 Use new simpler "TimeTypeEx", "StructTmEx" functions. */ /* 03/18/07 RLH 04 Enable GMT vs. LOC conversions to work on QNX; */ /* fix bug in Bool_StdTimeGmTimeR. */ /* 11/21/06 RLH 03 StdTimeRet no longer static, now in stdtime.c */ /* 06/07/06 RLH 02 Numerous features added, see stdtime.doc */ /* 01/18/06 RLH 01 Created */ /*****************************************************************************/ #include "stdtime.h" #define STDTIMEW32_FT_TIMET_SCALE 10000000 #define STDTIMEW32_FT_TIMET_BASE_HI 0x019DB1DE #define STDTIMEW32_FT_TIMET_BASE_LO 0xD53E8000 /*-***************************************************************************/ /* Bool_StdTimeGmTimeR - PRIVATE FUNCTION */ /* provide interface for gmtime_r where possible, otherwise gmtime. */ /* we provide thread safety for this function, if the operating system and */ /* runtime library allows for it. */ /*****************************************************************************/ STDTIME_BOOL Bool_StdTimeGmTimeR ( time_t * pTimeT, struct tm * pStructTm) { if ((pTimeT == NULL) || (pStructTm == NULL)) { return STDTIME_FALSE; } #ifdef STDTIME_REENTRANT_GMTIME_LOCALTIME if (gmtime_r (pTimeT, pStructTm) != 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #elif defined(STDTIME_MSVC8) #ifdef _USE_64BIT_TIME_T if (_gmtime64_s (pStructTm, (__time64_t *) pTimeT) == 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #else /* not _USE_64BIT_TIME_T */ if (_gmtime32_s (pStructTm, (__time32_t *) pTimeT) == 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #endif /* _USE_64BIT_TIME_T */ #else /* no reentrant gmtime available */ { struct tm * pTempTm = NULL; pTempTm = gmtime (pTimeT); if (pTempTm == NULL) { return STDTIME_FALSE; } /* copy back to caller */ *pStructTm = *pTempTm; return STDTIME_TRUE; } #endif } /* Bool_StdTimeGmTimeR */ /*-***************************************************************************/ /* Bool_StdTimeLocalTimeR - PRIVATE FUNCTION */ /* provide interface for localtime_r where possible, otherwise localtime. */ /* we provide thread safety for this function, if the operating system and */ /* runtime library allows for it. */ /*****************************************************************************/ STDTIME_BOOL Bool_StdTimeLocalTimeR ( time_t * pTimeT, struct tm * pStructTm) { if ((pTimeT == NULL) || (pStructTm == NULL)) { return STDTIME_FALSE; } #ifdef STDTIME_REENTRANT_GMTIME_LOCALTIME if (localtime_r (pTimeT, pStructTm) != 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #elif defined(STDTIME_MSVC8) #ifdef _USE_64BIT_TIME_T if (_localtime64_s (pStructTm, (__time64_t *) pTimeT) == 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #else /* not _USE_64BIT_TIME_T */ if (_localtime32_s (pStructTm, (__time32_t *) pTimeT) == 0) { return STDTIME_TRUE; } return STDTIME_FALSE; #endif /* _USE_64BIT_TIME_T */ #else /* no reentrant localtime available */ { struct tm * pTempTm = NULL; pTempTm = localtime (pTimeT); if (pTempTm == NULL) { return STDTIME_FALSE; } /* copy back to caller */ *pStructTm = *pTempTm; return STDTIME_TRUE; } #endif } /* Bool_StdTimeLocalTimeR */ #if 0 /* Int_StdTimeLocalDiff is obsolete */ /* function is obsolete as of 2007-03-18, will be removed in future release. */ /*-***************************************************************************/ /* Int_StdTimeLocalDiff - PRIVATE FUNCTION */ /* get difference in minutes of (GMT time) - (local time) */ /* in case gmtime() or localtime() fails, return 0 */ /*****************************************************************************/ static int32_t Int_StdTimeLocalDiff () { time_t gmt_time_t; struct tm locTm; struct tm gmtTm; int32_t locDay; int32_t gmtDay; int32_t locMin; int32_t gmtMin; int32_t diff; /* problem with this logic is that 'time(NULL)' returns current time */ /* so calculation of LOC vs. GMT is based on current time instead of */ /* the time value being converted. */ gmt_time_t = time(NULL); if (! Bool_StdTimeLocalTimeR (&gmt_time_t, &locTm)) { return 0; } locDay = ((locTm.tm_year) * 10000) + ((locTm.tm_mon) * 100) +(locTm.tm_mday); locMin = ((locTm.tm_hour) * 60) + locTm.tm_min; if (! Bool_StdTimeGmTimeR (&gmt_time_t, &gmtTm)) { return 0; } gmtDay = ((gmtTm.tm_year) * 10000) + ((gmtTm.tm_mon) * 100) +(gmtTm.tm_mday); gmtMin = ((gmtTm.tm_hour) * 60) + gmtTm.tm_min; if (locDay == gmtDay) { /* loc and gmt are in same day */ diff = gmtMin - locMin; } else if (gmtDay > locDay) { /* gmtDay > locDay, so gmtMin < locMin */ /* example: 2006-01-01 23:00 EST = 2006-01-02 04:00 GMT */ /* 04:00 GMT - 23:00 EST = difference of -19:00 but that is wrong. */ /* it should be a difference of +05:00 */ /* to correct, calculate (04:00+24:00) GMT - 23:00 EST = +05:00 */ /* note that adjustment is made in minutes */ diff = (gmtMin + 1440) - locMin; } else { /* gmtDay < locDay, so gmtMin > locMin */ /* example: 2006-01-02 01:00 MSK = 2006-01-01 22:00 GMT */ /* 22:00 GMT - 01:00 MSK = difference of +21:00 but that is wrong. */ /* it should be a difference of -03:00 */ /* to correct, calculate 22:00 GMT - (01:00+24:00) MSK = -03:00 */ /* note that adjustment is made in minutes */ diff = gmtMin - (locMin + 1440); } /* calculated difference value is in minutes */ /* for EST, diff = GMT-EST = 300 [ 5 hours ] */ /* for EDT, diff = GMT-EDT = 240 [ 4 hours ] */ return diff; } /* Int_StdTimeLocalDiff */ #endif /* Int_StdTimeLocalDiff is obsolete */ /*****************************************************************************/ /* StdTimeW32FileTimeToLocalFileTime */ /* portable implementation of WIN32 API FileTimeToLocalFileTime */ /*****************************************************************************/ STDTIMEW32_STATIC STDTIME_WIN_BOOL StdTimeW32FileTimeToLocalFileTime ( const STDTIME_WIN_FILETIME * /*I*/ pGmtFileTime, STDTIME_WIN_FILETIME * /*O*/ pLocFileTime) { STDTIME gmtStdTime; STDTIME locStdTime; STDTIME_RC rc; time_t gmtTimeT; struct tm * pStructTm; struct tm locStructTm; int32_t nsec; if ((pGmtFileTime == NULL) || (pLocFileTime == NULL)) { return STDTIME_WIN_FALSE; } rc = FileTimeToStdTime (pGmtFileTime, &gmtStdTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; rc = StdTimeToTimeTypeEx (&gmtStdTime, &gmtTimeT, &nsec); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; pStructTm = localtime (&gmtTimeT); if (pStructTm == NULL) return STDTIME_WIN_FALSE; locStructTm = *pStructTm; rc = StructTmExToStdTime (&locStructTm, nsec, &locStdTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; rc = StdTimeToFileTime (&locStdTime, pLocFileTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; return STDTIME_WIN_TRUE; } /* StdTimeW32FileTimeToLocalFileTime */ /*****************************************************************************/ /* StdTimeW32LocalFileTimeToFileTime */ /* portable implementation of WIN32 API LocalFileTimeToFileTime */ /*****************************************************************************/ STDTIMEW32_STATIC STDTIME_WIN_BOOL StdTimeW32LocalFileTimeToFileTime ( const STDTIME_WIN_FILETIME * /*I*/ pLocFileTime, STDTIME_WIN_FILETIME * /*O*/ pGmtFileTime) { STDTIME gmtStdTime; STDTIME locStdTime; STDTIME_RC rc; time_t gmtTimeT; struct tm locStructTm; int32_t nsec; if ((pGmtFileTime == NULL) || (pLocFileTime == NULL)) { return STDTIME_WIN_FALSE; } rc = FileTimeToStdTime (pLocFileTime, &locStdTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; rc = StdTimeToStructTmEx (&locStdTime, &locStructTm, &nsec); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; locStructTm.tm_isdst = -1; /* CRITICAL: make OS figure out if DST */ gmtTimeT = mktime (&locStructTm); if (gmtTimeT == (time_t) (-1)) return STDTIME_WIN_FALSE; rc = TimeTypeExToStdTime (gmtTimeT, nsec, &gmtStdTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; rc = StdTimeToFileTime (&gmtStdTime, pGmtFileTime); if (rc != STDTIME_OK) return STDTIME_WIN_FALSE; return STDTIME_WIN_TRUE; } /* StdTimeW32LocalFileTimeToFileTime */ /*****************************************************************************/ /* StdTimeW32_IsLeap - return 1 if leap year, else 0 */ /*****************************************************************************/ STDTIMEW32_STATIC int StdTimeW32_IsLeap (int year) { if ((year < 0 ) || (year > 32767)) { return 0; } if ((year % 4000) == 0) { return 0; /* multiples of 4000 are not leap years */ } if ((year % 400) == 0) { return 1; /* multiples of 400 are leap years */ } if ((year % 100) == 0) { return 0; /* multiples of 100 are not leap years */ } if ((year % 4) == 0) { return 1; /* multiples of 4 are leap years */ } return 0; /* all others are not leap years */ } /* StdTimeW32_IsLeap */ /*****************************************************************************/ /* StdTimeW32_LeapYearDays - number leap-year days based on year y */ /*****************************************************************************/ STDTIMEW32_STATIC int StdTimeW32_LeapYearDays (int y) { /* number of 4000-year multiples */ int n4000 = (y / 4000); /* number of 400-year multiples in excess of 4000 */ int n400 = (y % 4000) / 400; /* number of 100-year multiples in excess of 400 */ int n100 = (y % 400) / 100; /* number of 4-year multiples in excess of 100 */ int n4 = (y % 100) / 4; return ( 969 * n4000 ) + ( 97 * n400 ) + ( 24 * n100 ) + ( 1 * n4 ); } /* StdTimeW32_LeapYearDays */ /*****************************************************************************/ /* days-per-month table */ /*****************************************************************************/ static int StdTimeW32_DaysPerMon [13] = { 00, 31, /* JAN */ 28, /* FEB */ 31, /* MAR */ 30, /* APR */ 31, /* MAY */ 30, /* JUN */ 31, /* JUL */ 31, /* AUG */ 30, /* SEP */ 31, /* OCT */ 30, /* NOV */ 31 /* DEC */ }; /*****************************************************************************/ /* StdTimeW32SystemTimeToFileTimeEx */ /* portable implementation of WIN32 API SystemTimeToFileTime */ /*****************************************************************************/ STDTIMEW32_STATIC STDTIME_WIN_BOOL StdTimeW32SystemTimeToFileTimeEx ( const STDTIME_WIN_SYSTEMTIME * /*I*/ pSystemTime, STDTIME_WIN_FILETIME * /*O*/ pFileTime, int /*I*/ nsec, int /*I*/ usec) { QUADLIB_U64 uVal; QUADLIB_U64 uNum; STDTIME_WIN_SYSTEMTIME st; STDTIME_WIN_FILETIME ft; int i; int d; int basedays; if ((pSystemTime == NULL) || (pFileTime == NULL)) { return STDTIME_WIN_FALSE; } st = *pSystemTime; /* form # of days for year - will not overflow uVal.lo */ QUADLIB_U64_HI(uVal) = 0; QUADLIB_I64_LO(uVal) = (365 * st.wYear) + StdTimeW32_LeapYearDays (st.wYear); /* convert year/mon to days */ d = st.wDay; for (i=1; i < st.wMonth; i++) { d += StdTimeW32_DaysPerMon [i]; } if (st.wMonth > 2) { d += StdTimeW32_IsLeap (st.wYear); } /* calculate: uVal += (d - basedays - 1) */ /* == uVal = uVal + d - basedays - 1 == uVal + d - (basedays + 1); */ /* use the equivalence above to avoid one QUADLIB operation, since */ /* there is an overhead to using them under simulation. */ QUADLIB_U64_HI(uNum) = 0; QUADLIB_I64_LO(uNum) = d; QUADLIB_U64_ADD_EQ (uVal, uNum); basedays = (STDTIME_WIN_EPOCH_YEAR * 365) + StdTimeW32_LeapYearDays(STDTIME_WIN_EPOCH_YEAR); QUADLIB_I64_LO(uNum) = basedays + 1; QUADLIB_U64_SUB_EQ (uVal, uNum); /* calculate: uVal = (uVal * 24) + st.wHour; */ QUADLIB_U64_LO(uNum) = 24; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = st.wHour; QUADLIB_U64_ADD_EQ (uVal, uNum); /* calculate: uVal = (uVal * 60) + st.wMinute; */ QUADLIB_U64_LO(uNum) = 60; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = st.wMinute; QUADLIB_U64_ADD_EQ (uVal, uNum); /* calculate: uVal = (uVal * 60) + st.wSecond; */ QUADLIB_U64_LO(uNum) = 60; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = st.wSecond; QUADLIB_U64_ADD_EQ (uVal, uNum); /* calculate: uVal = (uVal * 1000) + st.wMilliseconds; */ QUADLIB_U64_LO(uNum) = 1000; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = st.wMilliseconds; QUADLIB_U64_ADD_EQ (uVal, uNum); /* calculate: uVal = (uVal * 1000) + usec; */ QUADLIB_U64_LO(uNum) = 1000; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = usec; QUADLIB_U64_ADD_EQ (uVal, uNum); /* calculate: uVal = (uVal * 10) + (nsec/100); */ QUADLIB_U64_LO(uNum) = 10; QUADLIB_U64_MUL_EQ (uVal, uNum); QUADLIB_U64_LO(uNum) = (nsec/100); QUADLIB_U64_ADD_EQ (uVal, uNum); ft.dwLowDateTime = QUADLIB_U64_LO(uVal); ft.dwHighDateTime = QUADLIB_U64_HI(uVal); *pFileTime = ft; return STDTIME_WIN_TRUE; } /* StdTimeW32SystemTimeToFileTimeEx */ /*****************************************************************************/ /* StdTimeW32SystemTimeToFileTime */ /* portable implementation of WIN32 API SystemTimeToFileTime */ /* convert SYSTEMTIME to FILETIME; usec and nsec values default to zero */ /*****************************************************************************/ STDTIMEW32_STATIC STDTIME_WIN_BOOL StdTimeW32SystemTimeToFileTime ( const STDTIME_WIN_SYSTEMTIME * /*I*/ pSystemTime, STDTIME_WIN_FILETIME * /*O*/ pFileTime) { return StdTimeW32SystemTimeToFileTimeEx (pSystemTime, pFileTime, 0, 0); } /* StdTimeW32SystemTimeToFileTime */ /*****************************************************************************/ /* StdTimeW32FileTimeToSystemTime */ /* portable implementation of WIN32 API FileTimeToSystemTime */ /*****************************************************************************/ STDTIMEW32_STATIC STDTIME_WIN_BOOL StdTimeW32FileTimeToSystemTime ( const STDTIME_WIN_FILETIME * /*I*/ pFileTime, STDTIME_WIN_SYSTEMTIME * /*O*/ pSystemTime) { QUADLIB_U64 uVal; QUADLIB_U64 uMod; QUADLIB_U64 uDiv; STDTIME_WIN_SYSTEMTIME st; STDTIME_WIN_FILETIME ft; int yday; int max_yday; int day; int mon; int nsec; int usec; int days; int year; int year_hi; int year_lo; int leap; int dpm; int basedays; int workdays; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4244) /* silence the VC compiler warning message: */ /* "conversion from 'int' to 'WORD', possible loss of data" */ #endif if ((pSystemTime == NULL) || (pFileTime == NULL)) { return STDTIME_WIN_FALSE; } ft = *pFileTime; QUADLIB_U64_HI(uVal) = ft.dwHighDateTime; QUADLIB_U64_LO(uVal) = ft.dwLowDateTime; /* uVal has count of 100 nsecs intervals */ /* calculate: nsec = (uVal % 10) * 100; */ QUADLIB_U64_HI(uDiv) = 0; QUADLIB_U64_LO(uDiv) = 10; uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); nsec = QUADLIB_I64_LO(uMod) * 100; /* uVal has usecs */ /* calculate: usec = uVal % 1000; */ QUADLIB_U64_LO(uDiv) = 1000; uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); usec = QUADLIB_I64_LO(uMod); /* uVal has msecs */ /* calculate: wMilliseconds = uVal % 1000; */ /* QUADLIB_U64_LO(uDiv) = 1000; ==> still in effect */ uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); st.wMilliseconds = QUADLIB_U64_LO(uMod); /* uVal has secs */ /* calculate: wSecond = uVal % 60; */ QUADLIB_U64_LO(uDiv) = 60; uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); st.wSecond = QUADLIB_U64_LO(uMod); /* uVal has mins */ /* calculate: wMinute = uVal % 60; */ /* QUADLIB_U64_LO(uDiv) = 60; ==> still in effect */ uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); st.wMinute = QUADLIB_U64_LO(uMod); /* uVal has hours */ /* calculate: wHour = uVal % 24; */ QUADLIB_U64_LO(uDiv) = 24; uVal = QuadLibU64DivMod (uVal, uDiv, &uMod); st.wHour = QUADLIB_U64_LO(uMod); /* uVal has days */ days = QUADLIB_I64_LO(uVal); /* Jan 1 1601 was a Monday (day number 1) */ /* determine day of week by adding base day number to relative 0 day */ /* modulus 7 is the day number */ st.wDayOfWeek = (days + 1) % 7; /* FT Epoch starts on Jan 1, 1601 */ /* calculate the number of days prior to FT Epoch */ /* treating year 0 as a year = start of year 0 to end of year 1600 */ /* which is 1601 years = 584753 */ basedays = (STDTIME_WIN_EPOCH_YEAR * 365) + StdTimeW32_LeapYearDays(STDTIME_WIN_EPOCH_YEAR); workdays = days + basedays; /* if we assumed every year were 365 days long, */ /* then workdays / 365 would calculate too high a year, whereas */ /* workdays / 366 would calculate too low a year */ /* determine year by forming an estimated year, then */ /* calculating its total days until we get the right number */ year_hi = (workdays / 365) + 1; year_lo = (workdays / 366) - 1; for (year = year_hi; year > year_lo; year--) { days = (year * 365) + StdTimeW32_LeapYearDays (year); if (days <= workdays) break; } if (year == year_lo) { /* failed to determine year */ return STDTIME_WIN_FALSE; } st.wYear = year; /* if 'days' == 6 (for example), then 6 complete days have */ /* elapsed, plus the number of fractional days (sec, msec, etc.) */ /* once fractional days exist, we are into the next day */ /* from a calendar point of view, the day is 'days+1' even if a */ /* day isn't over yet. */ /* however, at midnight (fractional days are exactly zero) */ /* it is assumed to be the start of the next day. */ /* so regardless, the day of year is days+1 always. */ yday = workdays - days + 1; leap = StdTimeW32_IsLeap (year); max_yday = 365 + leap; if ((yday < 1) || (yday > max_yday)) { /* yday is invalid for the given year */ return STDTIME_WIN_FALSE; } day = yday; for (mon=1; mon <= 12; mon++) { dpm = StdTimeW32_DaysPerMon [mon]; if (leap && (mon == 2)) dpm++; if (day <= dpm) break; day -= dpm; } if (mon > 12) { /* failed to determine month */ return STDTIME_WIN_FALSE; } st.wMonth = mon; st.wDay = day; *pSystemTime = st; return STDTIME_WIN_TRUE; #ifdef _MSC_VER #pragma warning(pop) #endif } /* StdTimeW32FileTimeToSystemTime */ /*****************************************************************************/ /* StdTimeW32GetDayofWeekAndYear */ /* get day of week, day of year from year, mon, day of month */ /* the maximum day number in the STDTIME system is about 3,652,500 */ /* so, there is no need for 64-bit math in this function, which only */ /* deals with days as the finest resolution. */ /*****************************************************************************/ STDTIME_RC StdTimeW32GetDayofWeekAndYear ( int32_t /*I*/ nYear, int32_t /*I*/ nMon, int32_t /*I*/ nDayofMon, int32_t * /*O*/ pDayofWeek, int32_t * /*O*/ pDayofYear) { int32_t n; int32_t yeardays; int32_t basedays; int32_t leap; int32_t nDayofWeek; int32_t nDayofYear; STDTIME_ENUM_FUNC (StdTimeW32GetDayofWeekAndYear) /* output fields are optional, but at least one must be present */ /* for the function to be considered successful */ if ((pDayofWeek == NULL) && (pDayofYear == NULL)) { STDTIME_RET_EC (null_argument); } if ((nYear < STDTIME_YEAR_MIN) || (nYear > STDTIME_YEAR_MAX)) { STDTIME_RET_EC (invalid_year); } if ((nMon < 1) || (nMon > 12)) { STDTIME_RET_EC (invalid_mon); } if (nDayofMon < 1) { STDTIME_RET_EC (invalid_day); } leap = StdTimeW32_IsLeap (nYear); n = StdTimeW32_DaysPerMon [nMon]; if (nMon == 2) { n += leap; } if (nDayofMon > n) { STDTIME_RET_EC (invalid_day); } /* form # of days for year - will not overflow 32 bits */ yeardays = (365 * nYear) + StdTimeW32_LeapYearDays (nYear-1); /* convert year/mon to days */ nDayofYear = nDayofMon; for (n=1; n < nMon; n++) { nDayofYear += StdTimeW32_DaysPerMon [n]; } if (nMon > 2) { nDayofYear += leap; } if (pDayofYear != NULL) { *pDayofYear = nDayofYear; } if (pDayofWeek == NULL) { STDTIME_RET_OK; /* nothing else to do */ } basedays = (STDTIME_WIN_EPOCH_YEAR * 365) + StdTimeW32_LeapYearDays(STDTIME_WIN_EPOCH_YEAR); yeardays += (nDayofYear - basedays - 1); /* uNum now contains a day number relative to January 1, 1601. */ /* it is known that this day was a Monday (day number == 1) */ /* so, to get day of week, form mod 7 of the day number + 1 */ /* and add 1 */ nDayofWeek = (yeardays + 1) % 7; *pDayofWeek = nDayofWeek; STDTIME_RET_OK; } /* StdTimeW32GetDayofWeekAndYear */ /*****************************************************************************/ /* gettimeofday() simulation on Win32 systems */ /*****************************************************************************/ #define STDTIMEW32_GETTIMEOFDAY_SUCCESS 0 #define STDTIMEW32_GETTIMEOFDAY_FAILURE (-1) #ifdef STDTIMEW32_USE_GETTIMEOFDAY #ifdef STDTIMEW32_DEBUGGING /* on Unix/Linux systems, gettimeofday() is defined in */ /* or */ #ifndef _WINSOCKAPI_ struct timeval { long tv_sec; /* seconds since Jan 1 1970 */ long tv_usec; /* microseconds (seconds / 1_000_000) */ }; #endif STDTIMEW32_STATIC int gettimeofday ( struct timeval *pTimeVal, void *pObsolete); /*****************************************************************************/ /* */ /* pObsolete as an argument is obsolete on most Unix/Linux systems, in */ /* which it is an error to specify a non-NULL value. */ /* */ /* gettimeofday() return codes */ /* rc 0: success */ /* rc -1: failure, errno set. */ /* errno: EFAULT pTimeVal points outside the accessible address space. */ /* errno: EINVAL The structure pointed to by 'pTimeVal' specifies an */ /* invalid time (not supported here) */ /* errno: EINVAL pObsolete argument is not NULL */ /* errno: EOVERFLOW: The system time is greater than 2038, cannot be stored.*/ /* Windows does not have EOVERFLOW in errno.h; ERANGE could be used, */ /* but for simulation purposes, this condition is not supported. */ /* */ /*****************************************************************************/ #endif /* STDTIMEW32_DEBUGGING */ #endif /* STDTIMEW32_USE_GETTIMEOFDAY */ /*****************************************************************************/ /* gettimeofday - simulate Unix/Linux function gettimeofday() */ /* function is used for debugging purposes only */ /*****************************************************************************/ #ifdef STDTIMEW32_USE_GETTIMEOFDAY #ifdef STDTIMEW32_DEBUGGING STDTIMEW32_STATIC int gettimeofday ( struct timeval *pTimeVal, void *pObsolete) { STDTIME_WIN_FILETIME ft; QUADLIB_U64 qFileTime; QUADLIB_U64 qSec; QUADLIB_U64 qNsec100; QUADLIB_U64 qNum; if (pTimeVal == NULL) { errno = EFAULT; return STDTIMEW32_GETTIMEOFDAY_FAILURE; } if (pObsolete != NULL) { /* the obsolete argument is not supposed to be used */ errno = EINVAL; return STDTIMEW32_GETTIMEOFDAY_FAILURE; } GetSystemTimeAsFileTime (&ft); QUADLIB_U64_HI(qFileTime) = ft.dwHighDateTime; QUADLIB_U64_LO(qFileTime) = ft.dwLowDateTime; /* conversion code adapted from MSDN KB Q167296 */ /* subtract epoch factor and divide by 10_000_000 */ QUADLIB_U64_HI(qNum) = STDTIMEW32_FT_TIMET_BASE_HI; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_BASE_LO; QUADLIB_I64_SUB_EQ (qFileTime, qNum); QUADLIB_U64_HI(qNum) = 0; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_SCALE; qSec = QuadLibU64DivMod (qFileTime, qNum, &qNsec100); pTimeVal->tv_sec = (long) QUADLIB_U64_LO(qSec); /* qNsec100 has multiples of 100 nanoseconds, or 1/10 microseconds */ /* to get whole microseconds, divide by 10 */ pTimeVal->tv_usec = (long) QUADLIB_U64_LO(qNsec100) / 10; return STDTIMEW32_GETTIMEOFDAY_SUCCESS; } /* gettimeofday */ #endif /* STDTIMEW32_DEBUGGING */ #endif /* STDTIMEW32_USE_GETTIMEOFDAY */ /*****************************************************************************/ /* StdTimeW32GetTimeOfDayToFileTime - interface Unix to Windows time */ /* function is used to replace WIN32 API GetSystemTimeAsFileTime */ /*****************************************************************************/ #ifdef STDTIMEW32_USE_GETTIMEOFDAY STDTIMEW32_STATIC void StdTimeW32GetTimeOfDayToFileTime (STDTIME_WIN_FILETIME *pFileTime) { QUADLIB_U64 qResult; QUADLIB_U64 qNum; struct timeval timeVal; STDTIME_WIN_FILETIME ft = {0}; /* since there is no return-code mechanism for the Windows API */ /* GetSystemTimeAsFileTime, we have none here. if the input */ /* parameter is NULL, the caller accepts the consequences. */ /* a call to GetSystemTimeAsFileTime(NULL) crashes on Windows */ if (gettimeofday (&timeVal, NULL) != STDTIMEW32_GETTIMEOFDAY_SUCCESS) { *pFileTime = ft; return; } /* multiply seconds result by 10_000_000 */ QUADLIB_U64_HI(qResult) = 0; QUADLIB_U64_LO(qResult) = timeVal.tv_sec; QUADLIB_U64_HI(qNum) = 0; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_SCALE; QUADLIB_U64_MUL_EQ (qResult, qNum); /* add 100nsec intervals by converting tv_usec to 100nsec */ /* note that 100nsec units = 10 * usec units */ /* there is no way to know if multiply by 10 will cause overflow */ /* in 32-bit mode, so quad lib used for this */ QUADLIB_U64_LO(qNum) = timeVal.tv_usec; QUADLIB_U64_MUL10_EQ (qNum); QUADLIB_U64_ADD_EQ (qResult, qNum); /* add constant difference in epoch values */ QUADLIB_U64_HI(qNum) = STDTIMEW32_FT_TIMET_BASE_HI; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_BASE_LO; QUADLIB_U64_ADD_EQ (qResult, qNum); ft.dwHighDateTime = QUADLIB_U64_HI(qResult); ft.dwLowDateTime = QUADLIB_U64_LO(qResult); *pFileTime = ft; } /* StdTimeW32GetTimeOfDayToFileTime */ #endif /* STDTIMEW32_USE_GETTIMEOFDAY */ /*****************************************************************************/ /* clock_gettime() simulation on Win32 systems */ /* StdTimeW32ClockGetTimeToFileTime - interface Unix to Windows time */ /*****************************************************************************/ #define STDTIMEW32_CLOCKGETTIME_SUCCESS 0 #define STDTIMEW32_CLOCKGETTIME_FAILURE (-1) #ifdef STDTIMEW32_USE_CLOCKGETTIME #ifdef STDTIMEW32_DEBUGGING /* clock_gettime is defined in Unix */ #ifndef _CLOCKID_T #define _CLOCKID_T typedef int clockid_t; #endif #ifndef _TIME_T_DEFINED typedef long time_t; #define _TIME_T_DEFINED #endif #define CLOCK_REALTIME 0 /* only CLOCK_REALTIME is supported in this simulation */ /*efine CLOCK_MONOTONIC 1 */ /*efine CLOCK_PROCESS_CPUTIME_ID 2 */ /*efine CLOCK_THREAD_CPUTIME_ID 3 */ struct timespec { time_t tv_sec; /* Seconds */ long tv_nsec; /* Nanoseconds */ }; STDTIMEW32_STATIC int clock_gettime (clockid_t clock_id, struct timespec *tp); /*****************************************************************************/ /* rc 0: success */ /* rc -1: failure, errno set. */ /* errno: EFAULT tp points outside the accessible address space. */ /* errno: EINVAL The clk_id specified is not supported on this system. */ /*****************************************************************************/ #endif /* STDTIMEW32_DEBUGGING */ #endif /* STDTIMEW32_USE_CLOCKGETTIME */ /*****************************************************************************/ /* clock_gettime - simulate Unix/Linux function clock_gettime() */ /*****************************************************************************/ #ifdef STDTIMEW32_USE_CLOCKGETTIME #ifdef STDTIMEW32_DEBUGGING STDTIMEW32_STATIC int clock_gettime ( clockid_t clock_id, struct timespec *pTimeSpec) { STDTIME_WIN_FILETIME ft; QUADLIB_U64 qFileTime; QUADLIB_U64 qSec; QUADLIB_U64 qNsec100; QUADLIB_U64 qNum; if (pTimeSpec == NULL) { errno = EFAULT; return STDTIMEW32_CLOCKGETTIME_FAILURE; } if (clock_id != CLOCK_REALTIME) { errno = EINVAL; return STDTIMEW32_CLOCKGETTIME_FAILURE; } GetSystemTimeAsFileTime (&ft); QUADLIB_U64_HI(qFileTime) = ft.dwHighDateTime; QUADLIB_U64_LO(qFileTime) = ft.dwLowDateTime; /* conversion code adapted from MSDN KB Q167296 */ /* subtract epoch factor and divide by 10_000_000 */ QUADLIB_U64_HI(qNum) = STDTIMEW32_FT_TIMET_BASE_HI; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_BASE_LO; QUADLIB_I64_SUB_EQ (qFileTime, qNum); QUADLIB_U64_HI(qNum) = 0; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_SCALE; qSec = QuadLibU64DivMod (qFileTime, qNum, &qNsec100); pTimeSpec->tv_sec = (long) QUADLIB_U64_LO(qSec); /* qNsec100 has multiples of 100 nanoseconds, or 1/10 microseconds */ /* to get whole nanoseconds, multiply by 100 */ /* since this value was calculated as a remainder, it will never */ /* exceed 10_000_000, so multiplying by 100 will always work */ pTimeSpec->tv_nsec = (long) QUADLIB_U64_LO(qNsec100) * 100; return 0; } /* clock_gettime */ #endif /* STDTIMEW32_DEBUGGING */ #endif /* STDTIMEW32_USE_CLOCKGETTIME */ /*****************************************************************************/ /* StdTimeW32ClockGetTimeToFileTime - interface Unix to Windows time */ /* function is used to replace WIN32 API GetSystemTimeAsFileTime */ /*****************************************************************************/ #ifdef STDTIMEW32_USE_CLOCKGETTIME STDTIMEW32_STATIC void StdTimeW32ClockGetTimeToFileTime ( STDTIME_WIN_FILETIME *pFileTime) { QUADLIB_U64 qResult; QUADLIB_U64 qNum; struct timespec timeSpec; STDTIME_WIN_FILETIME ft = {0}; /* since there is no return-code mechanism for the Windows API */ /* GetSystemTimeAsFileTime, we have none here. if the input */ /* parameter is NULL, the caller accepts the consequences. */ /* a call to GetSystemTimeAsFileTime(NULL) crashes on Windows */ if (clock_gettime (CLOCK_REALTIME, &timeSpec) != STDTIMEW32_CLOCKGETTIME_SUCCESS) { *pFileTime = ft; return; } /* multiply seconds result by 10_000_000 */ #if STDTIME_TIME_T64_ENABLED QUADLIB_U64_HI(qResult) = QUADLIB_U64_HI(timeSpec.tv_sec); QUADLIB_U64_LO(qResult) = QUADLIB_U64_LO(timeSpec.tv_sec); #else QUADLIB_U64_HI(qResult) = 0; QUADLIB_U64_LO(qResult) = (*(uint32_t *)(&(timeSpec.tv_sec))); #endif QUADLIB_U64_HI(qNum) = 0; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_SCALE; QUADLIB_U64_MUL_EQ (qResult, qNum); /* add 100nsec intervals by converting tv_nsec to 100nsec */ QUADLIB_U64_LO(qNum) = timeSpec.tv_nsec / 100; QUADLIB_U64_ADD_EQ (qResult, qNum); /* add constant difference in epoch values */ QUADLIB_U64_HI(qNum) = STDTIMEW32_FT_TIMET_BASE_HI; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_BASE_LO; QUADLIB_U64_ADD_EQ (qResult, qNum); ft.dwHighDateTime = QUADLIB_U64_HI(qResult); ft.dwLowDateTime = QUADLIB_U64_LO(qResult); *pFileTime = ft; } /* StdTimeW32ClockGetTimeToFileTime */ #endif /* STDTIMEW32_USE_CLOCKGETTIME */ /*****************************************************************************/ /* StdTimeW32TimeBToFileTime - interface Unix to Windows time */ /* function is used to replace WIN32 API GetSystemTimeAsFileTime */ /* */ /* ftime() and struct timeb exist on Windows and Unix */ /* however, a struct timeb has only millisecond precision, so there is */ /* no reason to use it on Windows, and would be used on Unix/Linux only */ /* if no better alternatives existed. */ /*****************************************************************************/ #ifdef STDTIMEW32_USE_TIMEB STDTIMEW32_STATIC void StdTimeW32TimeBToFileTime ( STDTIME_WIN_FILETIME *pFileTime) { QUADLIB_U64 qResult; QUADLIB_U64 qNum; struct timeb timeBuffer; STDTIME_WIN_FILETIME ft = {0}; /* since there is no return-code mechanism for the Windows API */ /* GetSystemTimeAsFileTime, we have none here. if the input */ /* parameter is NULL, the caller accepts the consequences. */ /* a call to GetSystemTimeAsFileTime(NULL) crashes on Windows */ ftime (&timeBuffer); /* ftime returns a time_t and a millisecond count */ /* since there is no further precision, the resulting FILETIME */ /* value will have zero for microseconds and nanoseconds */ /* multiply seconds result by 10_000_000 */ #if STDTIME_TIME_T64_ENABLED QUADLIB_U64_HI(qResult) = QUADLIB_U64_HI(timeBuffer.time); QUADLIB_U64_LO(qResult) = QUADLIB_U64_LO(timeBuffer.time); #else QUADLIB_U64_HI(qResult) = 0; QUADLIB_U64_LO(qResult) = (*(uint32_t *)(&(timeBuffer.time))); #endif QUADLIB_U64_HI(qNum) = 0; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_SCALE; QUADLIB_U64_MUL_EQ (qResult, qNum); /* add milliseconds after converting to 100-nanosecond intervals */ /* this requires multiplying an unsigned short by 10,000 */ /* the maximum value will not overflow an unsigned 32-bit value */ QUADLIB_U64_LO(qNum) = 10000 * (unsigned long) timeBuffer.millitm; QUADLIB_U64_ADD_EQ (qResult, qNum); /* add constant difference in epoch values */ QUADLIB_U64_HI(qNum) = STDTIMEW32_FT_TIMET_BASE_HI; QUADLIB_U64_LO(qNum) = STDTIMEW32_FT_TIMET_BASE_LO; QUADLIB_U64_ADD_EQ (qResult, qNum); ft.dwHighDateTime = QUADLIB_U64_HI(qResult); ft.dwLowDateTime = QUADLIB_U64_LO(qResult); *pFileTime = ft; } /* StdTimeW32TimeBToFileTime */ #endif /* STDTIMEW32_USE_TIMEB */