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.

283 lines
11 KiB

  1. /***
  2. *localtim.c - Convert time_t value to time structure
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Converts time stored as a time_t value to a structure of type
  8. * struct tm expressed as local time.
  9. *
  10. *Revision History:
  11. * 01-??-84 RLB Module created
  12. * 05-??-84 DCW split off from the rest of the ctime routines
  13. * 02-18-87 JCR made localtime work when gmtime returns null
  14. * 03-31-87 JCR fixed bug pertaining to uninitialized _isindst(tb)
  15. * 04-10-87 JCR changed long declaration to time_t and added const
  16. * 11-10-87 SKS Removed IBMC20 switch
  17. * 11-18-87 SKS Change tzset() to __tzset()
  18. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  19. * 11-06-89 KRS Added (unsigned) to handle years 2040-2099 correctly.
  20. * 03-20-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  21. * <cruntime.h>, removed #include <register.h> and
  22. * fixed the copyright. Also, cleaned up the formatting
  23. * a bit.
  24. * 10-04-90 GJF New-style function declarator. Also, rewrote expr.
  25. * to avoid using cast as lvalue.
  26. * 01-21-91 GJF ANSI naming.
  27. * 08-10-92 PBS Posix support (TZ stuff).
  28. * 03-24-93 GJF Ported C8-16 version and adapted for exotic Daylight
  29. * Savings Time conversions which are legal under POSIX.
  30. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  31. * 07-15-93 GJF Replaced _tzset() call with __tzset() call.
  32. * 09-20-93 GJF Merged NT SDK and Cuda version (amount to picking up
  33. * fixes to Posix build).
  34. * 11-04-93 GJF Picked up a fix for the Posix build.
  35. * 02-13-95 GJF Call _tzset for Mac builds (temp change?). Also,
  36. * picked up bug fix from Mac version (setting of
  37. * tm_yday field in underflow case).
  38. * 08-31-95 GJF Use _dstbias as the Daylight Saving Time bias and
  39. * all for the beginning or end of the Epoch to be in a
  40. * DST.
  41. * 02-07-98 GJF Changes for Win64: replaced long type with time_t,
  42. * added some int casts where required, also use __int64
  43. * max value for bounds checking.
  44. * 09-25-98 GJF Set tm_isdst, when appropriate, at beginning/end of the
  45. * Epoch
  46. * 05-17-99 PML Remove all Macintosh support.
  47. * 11-03-99 RDL Win64 POSIX warning fix.
  48. *
  49. *******************************************************************************/
  50. #include <cruntime.h>
  51. #include <limits.h>
  52. #include <time.h>
  53. #include <stddef.h>
  54. #include <ctime.h>
  55. #include <internal.h>
  56. /***
  57. *struct tm *localtime(ptime) - convert time_t value to tm structure
  58. *
  59. *Purpose:
  60. * Convert a value in internal (time_t) format to a tm struct
  61. * containing the corresponding local time.
  62. *
  63. * NOTES:
  64. * (1) gmtime must be called before _isindst to ensure that the tb time
  65. * structure is initialized.
  66. * (2) gmtime and localtime use a single statically allocated buffer.
  67. * Each call to one of these routines destroys the contents of the
  68. * previous call.
  69. * (3) It is assumed that time_t is a 32-bit long integer representing
  70. * the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the
  71. * Posix/Unix Epoch. Only non-negative values are supported.
  72. * (4) It is assumed that the maximum adjustment for local time is
  73. * less than three days (include Daylight Savings Time adjustment).
  74. * This only a concern in Posix where the specification of the TZ
  75. * environment restricts the combined offset for time zone and
  76. * Daylight Savings Time to 2 * (24:59:59), just under 50 hours.
  77. *
  78. *Entry:
  79. * time_t *ptime - pointer to a long time value
  80. *
  81. *Exit:
  82. * If *ptime is non-negative, returns a pointer to the tm structure.
  83. * Otherwise, returns NULL.
  84. *
  85. *Exceptions:
  86. * See items (3) and (4) in the NOTES above. If these assumptions are
  87. * violated, behavior is undefined.
  88. *
  89. *******************************************************************************/
  90. struct tm * __cdecl localtime (
  91. const time_t *ptime
  92. )
  93. {
  94. REG1 struct tm *ptm;
  95. time_t ltime;
  96. /*
  97. * Check for illegal time_t value
  98. */
  99. if ( *ptime < 0 )
  100. return( NULL );
  101. #ifdef _POSIX_
  102. tzset();
  103. #else
  104. __tzset();
  105. #endif
  106. #ifdef _WIN64
  107. if ( (*ptime > 3 * _DAY_SEC) && (*ptime < _I64_MAX - 3 * _DAY_SEC) ) {
  108. #else
  109. if ( (*ptime > 3 * _DAY_SEC) && (*ptime < LONG_MAX - 3 * _DAY_SEC) ) {
  110. #endif
  111. /*
  112. * The date does not fall within the first three, or last
  113. * three, representable days of the Epoch. Therefore, there
  114. * is no possibility of overflowing or underflowing the
  115. * time_t representation as we compensate for timezone and
  116. * Daylight Savings Time.
  117. */
  118. ltime = *ptime - _timezone;
  119. ptm = gmtime( &ltime );
  120. /*
  121. * Check and adjust for Daylight Saving Time.
  122. */
  123. if ( _daylight && _isindst( ptm ) ) {
  124. #ifdef _POSIX_
  125. ltime -= _dstoffset - _timezone;
  126. #else
  127. ltime -= _dstbias;
  128. #endif
  129. ptm = gmtime( &ltime );
  130. ptm->tm_isdst = 1;
  131. }
  132. }
  133. else {
  134. ptm = gmtime( ptime );
  135. /*
  136. * The date falls with the first three, or last three days
  137. * of the Epoch. It is possible the time_t representation
  138. * would overflow or underflow while compensating for
  139. * timezone and Daylight Savings Time. Therefore, make the
  140. * timezone and Daylight Savings Time adjustments directly
  141. * in the tm structure. The beginning of the Epoch is
  142. * 00:00:00, 01-01-70 (UTC) and the last representable second
  143. * in the Epoch is 03:14:07, 01-19-2038 (UTC). This will be
  144. * used in the calculations below.
  145. *
  146. * First, adjust for the timezone.
  147. */
  148. #ifdef _POSIX_
  149. ltime = (time_t)ptm->tm_sec - _timezone;
  150. #else
  151. if ( _daylight && _isindst(ptm) ) {
  152. ltime = (time_t)ptm->tm_sec - (_timezone + _dstbias);
  153. ptm->tm_isdst = 1;
  154. }
  155. else
  156. ltime = (time_t)ptm->tm_sec - _timezone;
  157. #endif
  158. ptm->tm_sec = (int)(ltime % 60);
  159. if ( ptm->tm_sec < 0 ) {
  160. ptm->tm_sec += 60;
  161. ltime -= 60;
  162. }
  163. ltime = (time_t)ptm->tm_min + ltime/60;
  164. ptm->tm_min = (int)(ltime % 60);
  165. if ( ptm->tm_min < 0 ) {
  166. ptm->tm_min += 60;
  167. ltime -= 60;
  168. }
  169. ltime = (time_t)ptm->tm_hour + ltime/60;
  170. ptm->tm_hour = (int)(ltime % 24);
  171. if ( ptm->tm_hour < 0 ) {
  172. ptm->tm_hour += 24;
  173. ltime -=24;
  174. }
  175. ltime /= 24;
  176. if ( ltime > 0 ) {
  177. /*
  178. * There is no possibility of overflowing the tm_mday
  179. * and tm_yday fields since the date can be no later
  180. * than January 19.
  181. */
  182. ptm->tm_wday = (ptm->tm_wday + (int)ltime) % 7;
  183. ptm->tm_mday += (int)ltime;
  184. ptm->tm_yday += (int)ltime;
  185. }
  186. else if ( ltime < 0 ) {
  187. /*
  188. * It is possible to underflow the tm_mday and tm_yday
  189. * fields. If this happens, then adjusted date must
  190. * lie in December 1969.
  191. */
  192. ptm->tm_wday = (ptm->tm_wday + 7 + (int)ltime) % 7;
  193. if ( (ptm->tm_mday += (int)ltime) <= 0 ) {
  194. ptm->tm_mday += 31;
  195. ptm->tm_yday = 364;
  196. ptm->tm_mon = 11;
  197. ptm->tm_year--;
  198. }
  199. else {
  200. ptm->tm_yday += (int)ltime;
  201. }
  202. }
  203. #ifdef _POSIX_
  204. /*
  205. * In Posix, it is possible either the first or last three
  206. * days of the Epoch might lie with Daylight Savings Time in
  207. * certain time zones.
  208. */
  209. if ( _isindst(ptm) ) {
  210. ltime = (long)ptm->tm_sec + _dstoffset;
  211. ptm->tm_sec = (int)(ltime % 60);
  212. if ( ptm->tm_sec < 0 ) {
  213. ptm->tm_sec += 60;
  214. ltime -= 60;
  215. }
  216. ltime = (long)ptm->tm_min + ltime/60;
  217. ptm->tm_min = (int)(ltime % 60);
  218. if ( ptm->tm_min < 0 ) {
  219. ptm->tm_min += 60;
  220. ltime -= 60;
  221. }
  222. ltime = (long)ptm->tm_hour + ltime/60;
  223. ptm->tm_hour = (int)(ltime % 24);
  224. if ( ptm->tm_hour < 0 ) {
  225. ptm->tm_hour += 24;
  226. ltime -=24;
  227. }
  228. ltime /= 24;
  229. if ( ltime > 0L ) {
  230. /*
  231. * There is no possibility of overflowing the
  232. * tm_mday and tm_yday fields since the date
  233. * can be no later than January 19.
  234. */
  235. ptm->tm_wday = (int)((ptm->tm_wday + ltime) % 7);
  236. ptm->tm_mday += (int)ltime;
  237. ptm->tm_yday += (int)ltime;
  238. }
  239. else if ( ltime < 0L ) {
  240. /*
  241. * It is possible to underflow the tm_mday
  242. * and tm_yday fields. If this happens, then
  243. * adjusted date must lie in December 1969.
  244. */
  245. ptm->tm_wday = (int)((ptm->tm_wday + 7 + ltime) % 7);
  246. if ( (ptm->tm_mday += (int)ltime) <= 0 ) {
  247. ptm->tm_mday += 31;
  248. ptm->tm_yday = 364;
  249. ptm->tm_mon = 11;
  250. ptm->tm_year--;
  251. }
  252. else {
  253. ptm->tm_yday += (int)ltime;
  254. }
  255. }
  256. }
  257. #endif
  258. }
  259. return(ptm);
  260. }