Files
microser/mmslib/util/stdtime_w32.c
2026-06-15 15:48:16 +08:00

1349 lines
38 KiB
C

/*****************************************************************************/
/* 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 */
/* <time.h> or <sys/time.h> */
#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 <time.h> */
#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 */