Windows NT 4.0 source code leak
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.

252 lines
6.8 KiB

4 years ago
  1. /***
  2. *localtim.c - Convert time_t value to time structure
  3. *
  4. * Copyright (c) 1985-1993, 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. * 07-15-93 GJF Replaced _tzset() call with __tzset() call.
  31. *
  32. *******************************************************************************/
  33. #include <cruntime.h>
  34. #include <limits.h>
  35. #include <time.h>
  36. #include <stddef.h>
  37. #include <ctime.h>
  38. #include <internal.h>
  39. /***
  40. *struct tm *localtime(ptime) - convert time_t value to tm structure
  41. *
  42. *Purpose:
  43. * Convert a value in internal (time_t) format to a tm struct
  44. * containing the corresponding local time.
  45. *
  46. * NOTES:
  47. * (1) gmtime must be called before _isindst to ensure that the tb time
  48. * structure is initialized.
  49. * (2) gmtime and localtime use a single statically allocated buffer.
  50. * Each call to one of these routines destroys the contents of the
  51. * previous call.
  52. * (3) It is assumed that time_t is a 32-bit long integer representing
  53. * the number of seconds since 00:00:00, 01-01-70 (UTC) (i.e., the
  54. * Posix/Unix Epoch. Only non-negative values are supported.
  55. * (4) It is assumed that the maximum adjustment for local time is
  56. * less than three days (include Daylight Savings Time adjustment).
  57. * This only a concern in Posix where the specification of the TZ
  58. * environment restricts the combined offset for time zone and
  59. * Daylight Savings Time to 2 * (24:59:59), just under 50 hours.
  60. *
  61. *Entry:
  62. * time_t *ptime - pointer to a long time value
  63. *
  64. *Exit:
  65. * If *ptime is non-negative, returns a pointer to the tm structure.
  66. * Otherwise, returns NULL.
  67. *
  68. *Exceptions:
  69. * See items (3) and (4) in the NOTES above. If these assumptions are
  70. * violated, behavior is undefined.
  71. *
  72. *******************************************************************************/
  73. struct tm * _CRTAPI1 localtime (
  74. const time_t *ptime
  75. )
  76. {
  77. REG1 struct tm *ptm;
  78. long ltime;
  79. /*
  80. * Check for illegal time_t value
  81. */
  82. if ( (long)*ptime < 0L )
  83. return( NULL );
  84. #ifdef _POSIX_
  85. tzset();
  86. #else
  87. __tzset();
  88. #endif
  89. if ( (*ptime > 3 * _DAY_SEC) && (*ptime < LONG_MAX - 3 * _DAY_SEC) ) {
  90. /*
  91. * The date does not fall within the first three, or last
  92. * three, representable days of the Epoch. Therefore, there
  93. * is no possibility of overflowing or underflowing the
  94. * time_t representation as we compensate for timezone and
  95. * Daylight Savings Time.
  96. */
  97. ltime = (long)*ptime - _timezone;
  98. ptm = gmtime( &ltime );
  99. /*
  100. * Check and adjust for Daylight Saving Time.
  101. */
  102. if ( _daylight && _isindst( ptm ) ) {
  103. #ifdef _POSIX_
  104. ltime -= _dstoffset - _timezone;
  105. #else
  106. ltime += 3600L;
  107. #endif
  108. ptm = gmtime( (time_t *)&ltime );
  109. ptm->tm_isdst = 1;
  110. }
  111. }
  112. else {
  113. ptm = gmtime( ptime );
  114. /*
  115. * The date falls with the first three, or last three days
  116. * of the Epoch. It is possible the time_t representation
  117. * would overflow or underflow while compensating for
  118. * timezone and Daylight Savings Time. Therefore, make the
  119. * timezone and Daylight Savings Time adjustments directly
  120. * in the tm structure. The beginning of the Epoch is
  121. * 00:00:00, 01-01-70 (UTC) and the last representable second
  122. * in theEpoch is 03:14:07, 01-19-2038 (UTC). This will be
  123. * used in the calculations below.
  124. *
  125. * First, adjust for the timezone.
  126. */
  127. ltime = (long)ptm->tm_sec - _timezone;
  128. ptm->tm_sec = (int)(ltime % 60);
  129. if ( ptm->tm_sec < 0 ) {
  130. ptm->tm_sec += 60;
  131. ltime -= 60;
  132. }
  133. ltime = (long)ptm->tm_min + ltime/60;
  134. ptm->tm_min = (int)(ltime % 60);
  135. if ( ptm->tm_min < 0 ) {
  136. ptm->tm_min += 60;
  137. ltime -= 60;
  138. }
  139. ltime = (long)ptm->tm_hour + ltime/60;
  140. ptm->tm_hour = (int)(ltime % 24);
  141. if ( ptm->tm_hour < 0 ) {
  142. ptm->tm_hour += 24;
  143. ltime -=24;
  144. }
  145. ltime /= 24;
  146. if ( ltime > 0L ) {
  147. /*
  148. * There is no possibility of overflowing the tm_mday
  149. * and tm_yday fields since the date can be no later
  150. * than January 19.
  151. */
  152. ptm->tm_wday = (ptm->tm_wday + ltime) % 7;
  153. ptm->tm_mday += ltime;
  154. ptm->tm_yday += ltime;
  155. }
  156. else if ( ltime < 0L ) {
  157. /*
  158. * It is possible to underflow the tm_mday and tm_yday
  159. * fields. If this happens, then adjusted date must
  160. * lie in December 1969.
  161. */
  162. ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7;
  163. if ( (ptm->tm_mday += ltime) <= 0 ) {
  164. ptm->tm_mday += 31;
  165. ptm->tm_yday = 365;
  166. ptm->tm_mon = 11;
  167. ptm->tm_year--;
  168. }
  169. else {
  170. ptm->tm_yday += ltime;
  171. }
  172. }
  173. #ifdef _POSIX_
  174. /*
  175. * In Posix, it is possible either the first or last three
  176. * days of the Epoch might lie with Daylight Savings Time in
  177. * certain time zones.
  178. */
  179. if ( _isindst(ptm) ) {
  180. ltime = (long)ptm->tm_sec + _dstoffset;
  181. ptm->tm_sec = (int)(ltime % 60);
  182. if ( ptm->tm_sec < 0 ) {
  183. ptm->tm_sec += 60;
  184. ltime -= 60;
  185. }
  186. ltime = (long)ptm->tm_min + ltime/60;
  187. ptm->tm_min = (int)(ltime % 60);
  188. if ( ptm->tm_min < 0 ) {
  189. ptm->tm_min += 60;
  190. ltime -= 60;
  191. }
  192. ltime = (long)ptm->tm_hour + ltime/60;
  193. ptm->tm_hour = (int)(ltime % 24);
  194. if ( ptm->tm_hour < 0 ) {
  195. ptm->tm_hour += 24;
  196. ltime -=24;
  197. }
  198. ltime /= 24;
  199. if ( ltime > 0L ) {
  200. /*
  201. * There is no possibility of overflowing the
  202. * tm_mday and tm_yday fields since the date
  203. * can be no later than January 19.
  204. */
  205. ptm->tm_wday = (ptm->tm_wday + ltime) % 7;
  206. ptm->tm_mday += ltime;
  207. ptm->tm_yday += ltime;
  208. }
  209. else if ( ltime < 0L ) {
  210. /*
  211. * It is possible to underflow the tm_mday
  212. * and tm_yday fields. If this happens, then
  213. * adjusted date must lie in December 1969.
  214. */
  215. ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7;
  216. if ( (ptm->tm_mday += ltime) <= 0 ) {
  217. ptm->tm_mday += 31;
  218. ptm->tm_yday = 365;
  219. ptm->tm_mon = 12;
  220. ptm->tm_year--;
  221. }
  222. else {
  223. ptm->tm_yday += ltime;
  224. }
  225. }
  226. }
  227. #endif
  228. }
  229. return(ptm);
  230. }