You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
499 lines
14 KiB
499 lines
14 KiB
/*++
|
|
|
|
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 <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <debuglib.h> // IF_DEBUG().
|
|
#include <time.h> // struct tm, time_t.
|
|
#include <malloc.h>
|
|
#include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates.
|
|
#include <prefix.h> // PREFIX_ equates.
|
|
#include <string.h>
|
|
#include <timelib.h> // My prototypes, NetpLocalTimeZoneOffset().
|
|
#include <lmerr.h> // NERR_InternalError, NO_ERROR, etc.
|
|
#include <stdlib.h>
|
|
|
|
|
|
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;
|
|
}
|