/*++ Copyright (c) 1991-1993 Microsoft Corporation Module Name: Time.c Abstract: This file contains the various time routines. Author: Dan Hinsley (DanHi) 12-Oct-1991 Environment: Interface is portable to any flat, 32-bit environment. (Uses Win32 typedefs.) Requires ANSI C extensions: slash-slash comments, long external names, _timezone global variable. Revision History: 12-Oct-1991 DanHi Created. (Moved from NetCmd\Map32 directory, file netlib.c) 28-Oct-1991 DanHi Moved net_asctime, net_gmtime and time_now from netcmd\map32\netlib.c to here. 20-Aug-1992 JohnRo RAID 2920: Support UTC timezone in net code. 01-Oct-1992 JohnRo RAID 3556: Added NetpSystemTimeToGmtTime() for DosPrint APIs. 15-Apr-1993 Danl Fixed NetpLocalTimeZoneOffset so that it uses the windows calls and obtains the correct bias. 14-Jun-1993 JohnRo RAID 13080: Allow repl between different timezones. Also, DanL asked me to remove printf() call. 18-Jun-1993 JohnRo RAID 13594: Extracted NetpLocalTimeZoneOffset() so srvsvc.dll doesn't get too big. Use NetpKdPrint() where possible. 09-Jul-1993 JohnRo RAID 15736: OS/2 time stamps are broken again (try rounding down). --*/ #include #include #include #include #include // IF_DEBUG(). #include // struct tm, time_t. #include #include // NetpAssert(), NetpKdPrint(), FORMAT_ equates. #include // PREFIX_ equates. #include #include // My prototypes, NetpLocalTimeZoneOffset(). #include // NERR_InternalError, NO_ERROR, etc. #include static int _lpdays[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; static int _days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; #define DaySec (24*60*60) #define YearSec (365*DaySec) #define DecSec 315532800 /* secs in 1970-1979 */ #define Day1 4 /* Jan. 1, 1970 was a Thursday */ #define Day180 2 /* Jan. 1, 1980 was a Tuesday */ int net_gmtime( time_t *Time, struct tm *TimeStruct ) /*++ Routine Description: This function is the same as the CRT gmtime except it takes the structure to fill as a user supplied parameter, sets the date to 1/1/80 if the time passed in is before that date and returns 1. Arguments: Time - Pointer to the number of seconds since 1970. TimeStruct - Pointer to the buffer to place the time struct. Return Value: 0 if date < 1/1/80, 1 otherwise. --*/ { LONG ac; /* accumulator */ int *mdays; /* pointer to days or lpdays */ int lpcnt; /* leap-year count */ if (*Time < (LONG) DecSec) { /* * Before 1980; convert it to 0:00:00 Jan 1, 1980 */ TimeStruct->tm_year = 80; TimeStruct->tm_mday = 1; TimeStruct->tm_mon = TimeStruct->tm_yday = TimeStruct->tm_isdst = 0; TimeStruct->tm_hour = TimeStruct->tm_min = TimeStruct->tm_sec = 0; TimeStruct->tm_wday = Day180; return(1); } /* * Make 1st try at determining year */ TimeStruct->tm_year = (int) (*Time / (LONG) YearSec); ac = (LONG)(*Time % (LONG) YearSec) - (lpcnt = (TimeStruct->tm_year + 1) / 4) * (LONG) DaySec; /* * Correct for leap-years passed since 1970. In the previous * calculation, since the lesser value of YearSec was used, (365 days) * for certain dates ac will be < 0 and tm_year will be too high. * (These dates will tend to be NEAR the end of December.) * This is fixed by adding years back into ac until it is >= 0. */ while (ac < 0) { ac += (LONG) YearSec; if (!((TimeStruct->tm_year + 1) % 4)) { ac += (LONG) DaySec; lpcnt--; } TimeStruct->tm_year--; } /* * See if this is a leap year */ TimeStruct->tm_year += 1970; if (!(TimeStruct->tm_year % 4) && ((TimeStruct->tm_year % 100) || !(TimeStruct->tm_year % 400))) /* Yes */ mdays = _lpdays; else /* No */ mdays = _days; /* * Put year in proper form. * Determine yday, month, hour, minute, and second. */ TimeStruct->tm_year -= 1900; TimeStruct->tm_yday = (int) (ac / (LONG) DaySec); ac %= (LONG) DaySec; for (TimeStruct->tm_mon = 1; mdays[TimeStruct->tm_mon] < TimeStruct->tm_yday; TimeStruct->tm_mon++) ; TimeStruct->tm_mday = TimeStruct->tm_yday - mdays[--TimeStruct->tm_mon]; TimeStruct->tm_hour = (int) (ac / 3600); ac %= 3600; TimeStruct->tm_min = (int) (ac / 60); TimeStruct->tm_sec = (int) (ac % 60); /* * Determine day of week */ TimeStruct->tm_wday = ((TimeStruct->tm_year-70)*365 + lpcnt + TimeStruct->tm_yday + Day1) % 7; TimeStruct->tm_isdst = 0; return(0); } DWORD time_now( VOID ) /*++ Routine Description: This function returns the UTC time in seconds since 1970. Arguments: None. Return Value: None. --*/ { LARGE_INTEGER Time; DWORD CurrentTime; // // Get the 64-bit system time. // Convert the system time to the number of seconds // since 1-1-1970. // NtQuerySystemTime(&Time); if (!RtlTimeToSecondsSince1970(&Time, &CurrentTime)) { CurrentTime = 0; } return CurrentTime; } VOID NetpGmtTimeToLocalTime( IN DWORD GmtTime, // seconds since 1970 (GMT), or 0, or -1. OUT LPDWORD LocalTime // seconds since 1970 (local), or, or -1. ) { NetpAssert( LocalTime != NULL ); if ( (GmtTime == 0) || (GmtTime == (DWORD)(-1)) ) { *LocalTime = GmtTime; // preserve 0 and -1 values. } else { *LocalTime = GmtTime - NetpLocalTimeZoneOffset(); } IF_DEBUG( TIME ) { NetpKdPrint(( PREFIX_NETLIB "NetpGmtTimeToLocalTime: done.\n" )); NetpDbgDisplayTimestamp( "gmt (in)", GmtTime ); NetpDbgDisplayTimestamp( "local (out)", *LocalTime ); } } // NetpGmtTimeToLocalTime VOID NetpLocalTimeToGmtTime( IN DWORD LocalTime, // seconds since 1970 (local), or 0, or -1. OUT LPDWORD GmtTime // seconds since 1970 (GMT), or 0, or -1. ) { NetpAssert( GmtTime != NULL ); if ( (LocalTime == 0) || (LocalTime == (DWORD)(-1)) ) { *GmtTime = LocalTime; // preserve 0 and -1 values. } else { *GmtTime = LocalTime + NetpLocalTimeZoneOffset(); } IF_DEBUG( TIME ) { NetpKdPrint(( PREFIX_NETLIB "NetpLocalTimeToGmtTime: done.\n" )); NetpDbgDisplayTimestamp( "local (in)", LocalTime ); NetpDbgDisplayTimestamp( "gmt (out)", *GmtTime ); } } // NetpLocalTimeToGmtTime NET_API_STATUS NetpSystemTimeToGmtTime( IN LPSYSTEMTIME WinSplitTime, OUT LPDWORD GmtTime // seconds since 1970 (GMT). ) { TIME_FIELDS NtSplitTime; LARGE_INTEGER NtPreciseTime; if ( (WinSplitTime==NULL) || (GmtTime==NULL) ) { return (ERROR_INVALID_PARAMETER); } NtSplitTime.Year = (CSHORT) WinSplitTime->wYear; NtSplitTime.Month = (CSHORT) WinSplitTime->wMonth; NtSplitTime.Day = (CSHORT) WinSplitTime->wDay; NtSplitTime.Hour = (CSHORT) WinSplitTime->wHour; NtSplitTime.Minute = (CSHORT) WinSplitTime->wMinute; NtSplitTime.Second = (CSHORT) WinSplitTime->wSecond; NtSplitTime.Milliseconds = (CSHORT) WinSplitTime->wMilliseconds; NtSplitTime.Weekday = (CSHORT) WinSplitTime->wDayOfWeek; if ( !RtlTimeFieldsToTime ( & NtSplitTime, // input & NtPreciseTime // output ) ) { NetpKdPrint(( PREFIX_NETLIB "NetpSystemTimeToGmtTime: RtlTimeFieldsToTime failed.\n" )); return (NERR_InternalError); } if ( !RtlTimeToSecondsSince1970 ( & NtPreciseTime, // input (PULONG) GmtTime ) ) { NetpKdPrint(( PREFIX_NETLIB "NetpSystemTimeToGmtTime: " "RtlTimeToSecondsSince1970 failed.\n" )); return (NERR_InternalError); } return (NO_ERROR); } // NetpSystemTimeToGmtTime VOID NetpGetTimeFormat( LPNET_TIME_FORMAT TimeFormat ) /*++ Routine Description: This function obtains the user-specific format for the time and date strings (short format). The format is returned in a structure pointed to by the TimeFormat parameter. MEMORY_USAGE ** IMPORTANT ** NOTE: This function expects any NON-NULL pointers in the TimeFormat structure to be allocated on the heap. It will attempt to free those pointers in order to update the format. This function allocates memory from the heap for the various structure members that are pointers to strings. It is the caller's responsiblilty to free each of these pointers. Arguments: TimeFormat - A pointer to a structure in which the format information can be stored. Return Value: --*/ { CHAR czParseString[MAX_TIME_SIZE]; LPSTR pTempString; INT numChars; LPSTR AMPMString=""; LPSTR ProfileLoc = "intl"; LPSTR emptyStr = ""; //----------------------------------------- // Get the Date Format (M/d/yy) //----------------------------------------- pTempString = czParseString; numChars = GetProfileStringA( ProfileLoc, "sShortDate", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars == 0) { // // No data, use the default. // pTempString = "M/d/yy"; numChars = strlen(pTempString); } if (TimeFormat->DateFormat != NULL) { LocalFree(TimeFormat->DateFormat); TimeFormat->DateFormat = NULL; } TimeFormat->DateFormat = LocalAlloc(LMEM_ZEROINIT, numChars+sizeof(CHAR)); if (TimeFormat->DateFormat != NULL) { strcpy(TimeFormat->DateFormat, pTempString); } //----------------------------------------- // 12 or 24 hour format? //----------------------------------------- TimeFormat->TwelveHour = TRUE; numChars = GetProfileStringA( ProfileLoc, "iTime", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars > 0) { if (*czParseString == '1'){ TimeFormat->TwelveHour = FALSE; } } //----------------------------------------- // Where put AMPM string? //----------------------------------------- TimeFormat->TimePrefix = FALSE; numChars = GetProfileStringA( ProfileLoc, "iTimePrefix", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars > 0) { if (*czParseString == '1'){ TimeFormat->TimePrefix = TRUE; } } //----------------------------------------- // Is there a Leading Zero? //----------------------------------------- TimeFormat->LeadingZero = FALSE; if (GetProfileIntA(ProfileLoc,"iTLZero",0) == 1) { TimeFormat->LeadingZero = TRUE; } //----------------------------------------- // Get the Time Separator character. //----------------------------------------- if (TimeFormat->TimeSeparator != NULL) { LocalFree(TimeFormat->TimeSeparator); TimeFormat->TimeSeparator = NULL; } numChars = GetProfileStringA( ProfileLoc, "sTime", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars == 0) { // // No data, use the default. // pTempString = ":"; numChars = strlen(pTempString); } else { pTempString = czParseString; } TimeFormat->TimeSeparator = LocalAlloc(LMEM_FIXED, numChars + sizeof(CHAR)); if (TimeFormat->TimeSeparator != NULL) { strcpy(TimeFormat->TimeSeparator, pTempString); } //------------------------------------------------- // Get the AM string. //------------------------------------------------- pTempString = czParseString; numChars = GetProfileStringA( ProfileLoc, "s1159", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars == 0) { pTempString = emptyStr; } if (TimeFormat->AMString != NULL) { LocalFree(TimeFormat->AMString); } TimeFormat->AMString = LocalAlloc(LMEM_FIXED,strlen(pTempString)+sizeof(CHAR)); if (TimeFormat->AMString != NULL) { strcpy(TimeFormat->AMString,pTempString); } //------------------------------------------------- // Get the PM string. //------------------------------------------------- pTempString = czParseString; numChars = GetProfileStringA( ProfileLoc, "s2359", emptyStr, czParseString, MAX_TIME_SIZE); if (numChars == 0) { pTempString = emptyStr; } if (TimeFormat->PMString != NULL) { LocalFree(TimeFormat->PMString); } TimeFormat->PMString = LocalAlloc(LMEM_FIXED,strlen(pTempString)+sizeof(WCHAR)); if (TimeFormat->PMString != NULL) { strcpy(TimeFormat->PMString,pTempString); } return; }