Source code of Windows XP (NT5)
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

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. Time.c
  5. Abstract:
  6. This file contains the various time routines.
  7. Author:
  8. Dan Hinsley (DanHi) 12-Oct-1991
  9. Environment:
  10. Interface is portable to any flat, 32-bit environment. (Uses Win32
  11. typedefs.) Requires ANSI C extensions: slash-slash comments, long
  12. external names, _timezone global variable.
  13. Revision History:
  14. 12-Oct-1991 DanHi
  15. Created. (Moved from NetCmd\Map32 directory, file netlib.c)
  16. 28-Oct-1991 DanHi
  17. Moved net_asctime, net_gmtime and time_now from netcmd\map32\netlib.c
  18. to here.
  19. 20-Aug-1992 JohnRo
  20. RAID 2920: Support UTC timezone in net code.
  21. 01-Oct-1992 JohnRo
  22. RAID 3556: Added NetpSystemTimeToGmtTime() for DosPrint APIs.
  23. 15-Apr-1993 Danl
  24. Fixed NetpLocalTimeZoneOffset so that it uses the windows calls and
  25. obtains the correct bias.
  26. 14-Jun-1993 JohnRo
  27. RAID 13080: Allow repl between different timezones.
  28. Also, DanL asked me to remove printf() call.
  29. 18-Jun-1993 JohnRo
  30. RAID 13594: Extracted NetpLocalTimeZoneOffset() so srvsvc.dll doesn't
  31. get too big.
  32. Use NetpKdPrint() where possible.
  33. 09-Jul-1993 JohnRo
  34. RAID 15736: OS/2 time stamps are broken again (try rounding down).
  35. --*/
  36. #include <nt.h>
  37. #include <ntrtl.h>
  38. #include <nturtl.h>
  39. #include <windows.h>
  40. #include <debuglib.h> // IF_DEBUG().
  41. #include <time.h> // struct tm, time_t.
  42. #include <malloc.h>
  43. #include <netdebug.h> // NetpAssert(), NetpKdPrint(), FORMAT_ equates.
  44. #include <prefix.h> // PREFIX_ equates.
  45. #include <string.h>
  46. #include <timelib.h> // My prototypes, NetpLocalTimeZoneOffset().
  47. #include <lmerr.h> // NERR_InternalError, NO_ERROR, etc.
  48. #include <stdlib.h>
  49. static int _lpdays[] = {
  50. -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  51. };
  52. static int _days[] = {
  53. -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
  54. };
  55. #define DaySec (24*60*60)
  56. #define YearSec (365*DaySec)
  57. #define DecSec 315532800 /* secs in 1970-1979 */
  58. #define Day1 4 /* Jan. 1, 1970 was a Thursday */
  59. #define Day180 2 /* Jan. 1, 1980 was a Tuesday */
  60. int
  61. net_gmtime(
  62. time_t *Time,
  63. struct tm *TimeStruct
  64. )
  65. /*++
  66. Routine Description:
  67. This function is the same as the CRT gmtime except it takes the structure
  68. to fill as a user supplied parameter, sets the date to 1/1/80 if the time
  69. passed in is before that date and returns 1.
  70. Arguments:
  71. Time - Pointer to the number of seconds since 1970.
  72. TimeStruct - Pointer to the buffer to place the time struct.
  73. Return Value:
  74. 0 if date < 1/1/80, 1 otherwise.
  75. --*/
  76. {
  77. LONG ac; /* accumulator */
  78. int *mdays; /* pointer to days or lpdays */
  79. int lpcnt; /* leap-year count */
  80. if (*Time < (LONG) DecSec) {
  81. /*
  82. * Before 1980; convert it to 0:00:00 Jan 1, 1980
  83. */
  84. TimeStruct->tm_year = 80;
  85. TimeStruct->tm_mday = 1;
  86. TimeStruct->tm_mon = TimeStruct->tm_yday = TimeStruct->tm_isdst = 0;
  87. TimeStruct->tm_hour = TimeStruct->tm_min = TimeStruct->tm_sec = 0;
  88. TimeStruct->tm_wday = Day180;
  89. return(1);
  90. }
  91. /*
  92. * Make 1st try at determining year
  93. */
  94. TimeStruct->tm_year = (int) (*Time / (LONG) YearSec);
  95. ac = (LONG)(*Time % (LONG) YearSec) - (lpcnt = (TimeStruct->tm_year + 1) / 4) *
  96. (LONG) DaySec;
  97. /*
  98. * Correct for leap-years passed since 1970. In the previous
  99. * calculation, since the lesser value of YearSec was used, (365 days)
  100. * for certain dates ac will be < 0 and tm_year will be too high.
  101. * (These dates will tend to be NEAR the end of December.)
  102. * This is fixed by adding years back into ac until it is >= 0.
  103. */
  104. while (ac < 0) {
  105. ac += (LONG) YearSec;
  106. if (!((TimeStruct->tm_year + 1) % 4)) {
  107. ac += (LONG) DaySec;
  108. lpcnt--;
  109. }
  110. TimeStruct->tm_year--;
  111. }
  112. /*
  113. * See if this is a leap year
  114. */
  115. TimeStruct->tm_year += 1970;
  116. if (!(TimeStruct->tm_year % 4) && ((TimeStruct->tm_year % 100) || !(TimeStruct->tm_year % 400)))
  117. /* Yes */
  118. mdays = _lpdays;
  119. else
  120. /* No */
  121. mdays = _days;
  122. /*
  123. * Put year in proper form.
  124. * Determine yday, month, hour, minute, and second.
  125. */
  126. TimeStruct->tm_year -= 1900;
  127. TimeStruct->tm_yday = (int) (ac / (LONG) DaySec);
  128. ac %= (LONG) DaySec;
  129. for (TimeStruct->tm_mon = 1; mdays[TimeStruct->tm_mon] < TimeStruct->tm_yday; TimeStruct->tm_mon++)
  130. ;
  131. TimeStruct->tm_mday = TimeStruct->tm_yday - mdays[--TimeStruct->tm_mon];
  132. TimeStruct->tm_hour = (int) (ac / 3600);
  133. ac %= 3600;
  134. TimeStruct->tm_min = (int) (ac / 60);
  135. TimeStruct->tm_sec = (int) (ac % 60);
  136. /*
  137. * Determine day of week
  138. */
  139. TimeStruct->tm_wday = ((TimeStruct->tm_year-70)*365 + lpcnt + TimeStruct->tm_yday + Day1) % 7;
  140. TimeStruct->tm_isdst = 0;
  141. return(0);
  142. }
  143. DWORD
  144. time_now(
  145. VOID
  146. )
  147. /*++
  148. Routine Description:
  149. This function returns the UTC time in seconds since 1970.
  150. Arguments:
  151. None.
  152. Return Value:
  153. None.
  154. --*/
  155. {
  156. LARGE_INTEGER Time;
  157. DWORD CurrentTime;
  158. //
  159. // Get the 64-bit system time.
  160. // Convert the system time to the number of seconds
  161. // since 1-1-1970.
  162. //
  163. NtQuerySystemTime(&Time);
  164. if (!RtlTimeToSecondsSince1970(&Time, &CurrentTime))
  165. {
  166. CurrentTime = 0;
  167. }
  168. return CurrentTime;
  169. }
  170. VOID
  171. NetpGmtTimeToLocalTime(
  172. IN DWORD GmtTime, // seconds since 1970 (GMT), or 0, or -1.
  173. OUT LPDWORD LocalTime // seconds since 1970 (local), or, or -1.
  174. )
  175. {
  176. NetpAssert( LocalTime != NULL );
  177. if ( (GmtTime == 0) || (GmtTime == (DWORD)(-1)) ) {
  178. *LocalTime = GmtTime; // preserve 0 and -1 values.
  179. } else {
  180. *LocalTime = GmtTime - NetpLocalTimeZoneOffset();
  181. }
  182. IF_DEBUG( TIME ) {
  183. NetpKdPrint(( PREFIX_NETLIB
  184. "NetpGmtTimeToLocalTime: done.\n" ));
  185. NetpDbgDisplayTimestamp( "gmt (in)", GmtTime );
  186. NetpDbgDisplayTimestamp( "local (out)", *LocalTime );
  187. }
  188. } // NetpGmtTimeToLocalTime
  189. VOID
  190. NetpLocalTimeToGmtTime(
  191. IN DWORD LocalTime, // seconds since 1970 (local), or 0, or -1.
  192. OUT LPDWORD GmtTime // seconds since 1970 (GMT), or 0, or -1.
  193. )
  194. {
  195. NetpAssert( GmtTime != NULL );
  196. if ( (LocalTime == 0) || (LocalTime == (DWORD)(-1)) ) {
  197. *GmtTime = LocalTime; // preserve 0 and -1 values.
  198. } else {
  199. *GmtTime = LocalTime + NetpLocalTimeZoneOffset();
  200. }
  201. IF_DEBUG( TIME ) {
  202. NetpKdPrint(( PREFIX_NETLIB
  203. "NetpLocalTimeToGmtTime: done.\n" ));
  204. NetpDbgDisplayTimestamp( "local (in)", LocalTime );
  205. NetpDbgDisplayTimestamp( "gmt (out)", *GmtTime );
  206. }
  207. } // NetpLocalTimeToGmtTime
  208. NET_API_STATUS
  209. NetpSystemTimeToGmtTime(
  210. IN LPSYSTEMTIME WinSplitTime,
  211. OUT LPDWORD GmtTime // seconds since 1970 (GMT).
  212. )
  213. {
  214. TIME_FIELDS NtSplitTime;
  215. LARGE_INTEGER NtPreciseTime;
  216. if ( (WinSplitTime==NULL) || (GmtTime==NULL) ) {
  217. return (ERROR_INVALID_PARAMETER);
  218. }
  219. NtSplitTime.Year = (CSHORT) WinSplitTime->wYear;
  220. NtSplitTime.Month = (CSHORT) WinSplitTime->wMonth;
  221. NtSplitTime.Day = (CSHORT) WinSplitTime->wDay;
  222. NtSplitTime.Hour = (CSHORT) WinSplitTime->wHour;
  223. NtSplitTime.Minute = (CSHORT) WinSplitTime->wMinute;
  224. NtSplitTime.Second = (CSHORT) WinSplitTime->wSecond;
  225. NtSplitTime.Milliseconds = (CSHORT) WinSplitTime->wMilliseconds;
  226. NtSplitTime.Weekday = (CSHORT) WinSplitTime->wDayOfWeek;
  227. if ( !RtlTimeFieldsToTime (
  228. & NtSplitTime, // input
  229. & NtPreciseTime // output
  230. ) ) {
  231. NetpKdPrint(( PREFIX_NETLIB
  232. "NetpSystemTimeToGmtTime: RtlTimeFieldsToTime failed.\n" ));
  233. return (NERR_InternalError);
  234. }
  235. if ( !RtlTimeToSecondsSince1970 (
  236. & NtPreciseTime, // input
  237. (PULONG) GmtTime ) ) {
  238. NetpKdPrint(( PREFIX_NETLIB
  239. "NetpSystemTimeToGmtTime: "
  240. "RtlTimeToSecondsSince1970 failed.\n" ));
  241. return (NERR_InternalError);
  242. }
  243. return (NO_ERROR);
  244. } // NetpSystemTimeToGmtTime
  245. VOID
  246. NetpGetTimeFormat(
  247. LPNET_TIME_FORMAT TimeFormat
  248. )
  249. /*++
  250. Routine Description:
  251. This function obtains the user-specific format for the time and date
  252. strings (short format). The format is returned in a structure
  253. pointed to by the TimeFormat parameter.
  254. MEMORY_USAGE ** IMPORTANT **
  255. NOTE: This function expects any NON-NULL pointers in the TimeFormat
  256. structure to be allocated on the heap. It will attempt to free those
  257. pointers in order to update the format. This function allocates memory
  258. from the heap for the various structure members that are pointers to
  259. strings. It is the caller's responsiblilty to free each of these
  260. pointers.
  261. Arguments:
  262. TimeFormat - A pointer to a structure in which the format information
  263. can be stored.
  264. Return Value:
  265. --*/
  266. {
  267. CHAR czParseString[MAX_TIME_SIZE];
  268. LPSTR pTempString;
  269. INT numChars;
  270. LPSTR AMPMString="";
  271. LPSTR ProfileLoc = "intl";
  272. LPSTR emptyStr = "";
  273. //-----------------------------------------
  274. // Get the Date Format (M/d/yy)
  275. //-----------------------------------------
  276. pTempString = czParseString;
  277. numChars = GetProfileStringA(
  278. ProfileLoc,
  279. "sShortDate",
  280. emptyStr,
  281. czParseString,
  282. MAX_TIME_SIZE);
  283. if (numChars == 0) {
  284. //
  285. // No data, use the default.
  286. //
  287. pTempString = "M/d/yy";
  288. numChars = strlen(pTempString);
  289. }
  290. if (TimeFormat->DateFormat != NULL) {
  291. LocalFree(TimeFormat->DateFormat);
  292. TimeFormat->DateFormat = NULL;
  293. }
  294. TimeFormat->DateFormat = LocalAlloc(LMEM_ZEROINIT, numChars+sizeof(CHAR));
  295. if (TimeFormat->DateFormat != NULL) {
  296. strcpy(TimeFormat->DateFormat, pTempString);
  297. }
  298. //-----------------------------------------
  299. // 12 or 24 hour format?
  300. //-----------------------------------------
  301. TimeFormat->TwelveHour = TRUE;
  302. numChars = GetProfileStringA(
  303. ProfileLoc,
  304. "iTime",
  305. emptyStr,
  306. czParseString,
  307. MAX_TIME_SIZE);
  308. if (numChars > 0) {
  309. if (*czParseString == '1'){
  310. TimeFormat->TwelveHour = FALSE;
  311. }
  312. }
  313. //-----------------------------------------
  314. // Where put AMPM string?
  315. //-----------------------------------------
  316. TimeFormat->TimePrefix = FALSE;
  317. numChars = GetProfileStringA(
  318. ProfileLoc,
  319. "iTimePrefix",
  320. emptyStr,
  321. czParseString,
  322. MAX_TIME_SIZE);
  323. if (numChars > 0) {
  324. if (*czParseString == '1'){
  325. TimeFormat->TimePrefix = TRUE;
  326. }
  327. }
  328. //-----------------------------------------
  329. // Is there a Leading Zero?
  330. //-----------------------------------------
  331. TimeFormat->LeadingZero = FALSE;
  332. if (GetProfileIntA(ProfileLoc,"iTLZero",0) == 1) {
  333. TimeFormat->LeadingZero = TRUE;
  334. }
  335. //-----------------------------------------
  336. // Get the Time Separator character.
  337. //-----------------------------------------
  338. if (TimeFormat->TimeSeparator != NULL) {
  339. LocalFree(TimeFormat->TimeSeparator);
  340. TimeFormat->TimeSeparator = NULL;
  341. }
  342. numChars = GetProfileStringA(
  343. ProfileLoc,
  344. "sTime",
  345. emptyStr,
  346. czParseString,
  347. MAX_TIME_SIZE);
  348. if (numChars == 0) {
  349. //
  350. // No data, use the default.
  351. //
  352. pTempString = ":";
  353. numChars = strlen(pTempString);
  354. }
  355. else {
  356. pTempString = czParseString;
  357. }
  358. TimeFormat->TimeSeparator = LocalAlloc(LMEM_FIXED, numChars + sizeof(CHAR));
  359. if (TimeFormat->TimeSeparator != NULL) {
  360. strcpy(TimeFormat->TimeSeparator, pTempString);
  361. }
  362. //-------------------------------------------------
  363. // Get the AM string.
  364. //-------------------------------------------------
  365. pTempString = czParseString;
  366. numChars = GetProfileStringA(
  367. ProfileLoc,
  368. "s1159",
  369. emptyStr,
  370. czParseString,
  371. MAX_TIME_SIZE);
  372. if (numChars == 0) {
  373. pTempString = emptyStr;
  374. }
  375. if (TimeFormat->AMString != NULL) {
  376. LocalFree(TimeFormat->AMString);
  377. }
  378. TimeFormat->AMString = LocalAlloc(LMEM_FIXED,strlen(pTempString)+sizeof(CHAR));
  379. if (TimeFormat->AMString != NULL) {
  380. strcpy(TimeFormat->AMString,pTempString);
  381. }
  382. //-------------------------------------------------
  383. // Get the PM string.
  384. //-------------------------------------------------
  385. pTempString = czParseString;
  386. numChars = GetProfileStringA(
  387. ProfileLoc,
  388. "s2359",
  389. emptyStr,
  390. czParseString,
  391. MAX_TIME_SIZE);
  392. if (numChars == 0) {
  393. pTempString = emptyStr;
  394. }
  395. if (TimeFormat->PMString != NULL) {
  396. LocalFree(TimeFormat->PMString);
  397. }
  398. TimeFormat->PMString = LocalAlloc(LMEM_FIXED,strlen(pTempString)+sizeof(WCHAR));
  399. if (TimeFormat->PMString != NULL) {
  400. strcpy(TimeFormat->PMString,pTempString);
  401. }
  402. return;
  403. }