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.

330 lines
10 KiB

  1. /***
  2. *mktime.c - Convert struct tm value to time_t value.
  3. *
  4. * Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines mktime() and _mkgmtime(), routines to converts a time value
  8. * in a tm structure (possibly incomplete) into a time_t value, then
  9. * update (all) the structure fields with "normalized" values.
  10. *
  11. *Revision History:
  12. * 01-14-87 JCR Module created
  13. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  14. * 06-15-89 PHG Now allows negative values and does DST by ANSI rules
  15. * 11-06-89 KRS Added (unsigned) to handle years 2040-2099 correctly.
  16. * 03-20-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  17. * <cruntime.h> and fixed the copyright. Also, cleaned
  18. * up the formatting a bit.
  19. * 10-04-90 GJF New-style function declarator. Also, rewrote expr.
  20. * to avoid using casts as lvalues.
  21. * 10-26-90 GJF Added ulscount to avoid overflows. Ugly, temporary
  22. * hack (whole function needs to be revised for ANSI
  23. * conformance).
  24. * 01-22-91 GJF ANSI naming.
  25. * 03-24-93 GJF Propagated changes from 16-bit tree. Modified to
  26. * expose _mkgmtime() routine.
  27. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  28. * 07-15-93 GJF Replaced _tzset() call with __tzset() call.
  29. * 09-13-93 GJF Merged NT SDK and Cuda versions (amounted to picking
  30. * up MattBr's changes to the Posix build made last
  31. * April).
  32. * 02-10-95 GJF Conditionally call _tzset instead of __tzset for Mac
  33. * builds (probably temporary change).
  34. * 05-09-95 GJF Properly handle initial tm_mon values from -11 to -1.
  35. * 08-31-95 GJF Use _dstbias for Daylight Saving Time bias instead of
  36. * -3600L.
  37. * 05-17-99 PML Remove all Macintosh support.
  38. * 08-30-99 PML long -> time_t in a few casts.
  39. *
  40. *******************************************************************************/
  41. #include <cruntime.h>
  42. #include <stddef.h>
  43. #include <ctime.h>
  44. #include <time.h>
  45. #include <internal.h>
  46. /*
  47. * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
  48. */
  49. #define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) \
  50. && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) )
  51. /*
  52. * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
  53. */
  54. #define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 )
  55. /*
  56. * Core function for both mktime() and _mkgmtime()
  57. */
  58. static time_t __cdecl _make_time_t( struct tm *, int);
  59. /***
  60. *time_t mktime(tb) - Normalize user time block structure
  61. *
  62. *Purpose:
  63. * Mktime converts a time structure, passed in as an argument, into a
  64. * calendar time value in internal format (time_t). It also completes
  65. * and updates the fields the of the passed in structure with 'normalized'
  66. * values. There are three practical uses for this routine:
  67. *
  68. * (1) Convert broken-down time to internal time format (time_t).
  69. * (2) To have mktime fill in the tm_wday, tm_yday, or tm_isdst fields.
  70. * (3) To pass in a time structure with 'out of range' values for some
  71. * fields and have mktime "normalize" them (e.g., pass in 1/35/87 and
  72. * get back 2/4/87).
  73. *Entry:
  74. * struct tm *tb - pointer to a tm time structure to convert and
  75. * normalize
  76. *
  77. *Exit:
  78. * If successful, mktime returns the specified calender time encoded as
  79. * a time_t value. Otherwise, (time_t)(-1) is returned to indicate an
  80. * error.
  81. *
  82. *Exceptions:
  83. * None.
  84. *
  85. *******************************************************************************/
  86. time_t __cdecl mktime (
  87. struct tm *tb
  88. )
  89. {
  90. return( _make_time_t(tb, 1) );
  91. }
  92. /***
  93. *time_t _mkgmtime(tb) - Convert broken down UTC time to time_t
  94. *
  95. *Purpose:
  96. * Convert a tm structure, passed in as an argument, containing a UTC
  97. * time value to internal format (time_t). It also completes and updates
  98. * the fields the of the passed in structure with 'normalized' values.
  99. *Entry:
  100. * struct tm *tb - pointer to a tm time structure to convert and
  101. * normalize
  102. *
  103. *Exit:
  104. * If successful, _mkgmtime returns the calender time encoded as time_t
  105. * Otherwise, (time_t)(-1) is returned to indicate an error.
  106. *
  107. *Exceptions:
  108. * None.
  109. *
  110. *******************************************************************************/
  111. time_t __cdecl _mkgmtime (
  112. struct tm *tb
  113. )
  114. {
  115. return( _make_time_t(tb, 0) );
  116. }
  117. /***
  118. *static time_t make_time_t(tb, ultflag) -
  119. *
  120. *Purpose:
  121. * Converts a struct tm value to a time_t value, then updates the struct
  122. * tm value. Either local time or UTC is supported, based on ultflag.
  123. * This is the routine that actually does the work for both mktime() and
  124. * _mkgmtime().
  125. *
  126. *Entry:
  127. * struct tm *tb - pointer to a tm time structure to convert and
  128. * normalize
  129. * int ultflag - use local time flag. the tb structure is assumed
  130. * to represent a local date/time if ultflag > 0.
  131. * otherwise, UTC is assumed.
  132. *
  133. *Exit:
  134. * If successful, mktime returns the specified calender time encoded as
  135. * a time_t value. Otherwise, (time_t)(-1) is returned to indicate an
  136. * error.
  137. *
  138. *Exceptions:
  139. * None.
  140. *
  141. *******************************************************************************/
  142. static time_t __cdecl _make_time_t (
  143. struct tm *tb,
  144. int ultflag
  145. )
  146. {
  147. time_t tmptm1, tmptm2, tmptm3;
  148. struct tm *tbtemp;
  149. /*
  150. * First, make sure tm_year is reasonably close to being in range.
  151. */
  152. if ( ((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR
  153. + 1) )
  154. goto err_mktime;
  155. /*
  156. * Adjust month value so it is in the range 0 - 11. This is because
  157. * we don't know how many days are in months 12, 13, 14, etc.
  158. */
  159. if ( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) {
  160. /*
  161. * no danger of overflow because the range check above.
  162. */
  163. tmptm1 += (tb->tm_mon / 12);
  164. if ( (tb->tm_mon %= 12) < 0 ) {
  165. tb->tm_mon += 12;
  166. tmptm1--;
  167. }
  168. /*
  169. * Make sure year count is still in range.
  170. */
  171. if ( (tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1) )
  172. goto err_mktime;
  173. }
  174. /***** HERE: tmptm1 holds number of elapsed years *****/
  175. /*
  176. * Calculate days elapsed minus one, in the given year, to the given
  177. * month. Check for leap year and adjust if necessary.
  178. */
  179. tmptm2 = _days[tb->tm_mon];
  180. if ( !(tmptm1 & 3) && (tb->tm_mon > 1) )
  181. tmptm2++;
  182. /*
  183. * Calculate elapsed days since base date (midnight, 1/1/70, UTC)
  184. *
  185. *
  186. * 365 days for each elapsed year since 1970, plus one more day for
  187. * each elapsed leap year. no danger of overflow because of the range
  188. * check (above) on tmptm1.
  189. */
  190. tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2)
  191. - _LEAP_YEAR_ADJUST;
  192. /*
  193. * elapsed days to current month (still no possible overflow)
  194. */
  195. tmptm3 += tmptm2;
  196. /*
  197. * elapsed days to current date. overflow is now possible.
  198. */
  199. tmptm1 = tmptm3 + (tmptm2 = (time_t)(tb->tm_mday));
  200. if ( ChkAdd(tmptm1, tmptm3, tmptm2) )
  201. goto err_mktime;
  202. /***** HERE: tmptm1 holds number of elapsed days *****/
  203. /*
  204. * Calculate elapsed hours since base date
  205. */
  206. tmptm2 = tmptm1 * 24L;
  207. if ( ChkMul(tmptm2, tmptm1, 24L) )
  208. goto err_mktime;
  209. tmptm1 = tmptm2 + (tmptm3 = (time_t)tb->tm_hour);
  210. if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
  211. goto err_mktime;
  212. /***** HERE: tmptm1 holds number of elapsed hours *****/
  213. /*
  214. * Calculate elapsed minutes since base date
  215. */
  216. tmptm2 = tmptm1 * 60L;
  217. if ( ChkMul(tmptm2, tmptm1, 60L) )
  218. goto err_mktime;
  219. tmptm1 = tmptm2 + (tmptm3 = (time_t)tb->tm_min);
  220. if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
  221. goto err_mktime;
  222. /***** HERE: tmptm1 holds number of elapsed minutes *****/
  223. /*
  224. * Calculate elapsed seconds since base date
  225. */
  226. tmptm2 = tmptm1 * 60L;
  227. if ( ChkMul(tmptm2, tmptm1, 60L) )
  228. goto err_mktime;
  229. tmptm1 = tmptm2 + (tmptm3 = (time_t)tb->tm_sec);
  230. if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
  231. goto err_mktime;
  232. /***** HERE: tmptm1 holds number of elapsed seconds *****/
  233. if ( ultflag ) {
  234. /*
  235. * Adjust for timezone. No need to check for overflow since
  236. * localtime() will check its arg value
  237. */
  238. #ifdef _POSIX_
  239. tzset();
  240. #else
  241. __tzset();
  242. #endif
  243. tmptm1 += _timezone;
  244. /*
  245. * Convert this second count back into a time block structure.
  246. * If localtime returns NULL, return an error.
  247. */
  248. if ( (tbtemp = localtime(&tmptm1)) == NULL )
  249. goto err_mktime;
  250. /*
  251. * Now must compensate for DST. The ANSI rules are to use the
  252. * passed-in tm_isdst flag if it is non-negative. Otherwise,
  253. * compute if DST applies. Recall that tbtemp has the time without
  254. * DST compensation, but has set tm_isdst correctly.
  255. */
  256. if ( (tb->tm_isdst > 0) || ((tb->tm_isdst < 0) &&
  257. (tbtemp->tm_isdst > 0)) ) {
  258. #ifdef _POSIX_
  259. tmptm1 -= _timezone;
  260. tmptm1 += _dstoffset;
  261. #else
  262. tmptm1 += _dstbias;
  263. #endif
  264. tbtemp = localtime(&tmptm1); /* reconvert, can't get NULL */
  265. }
  266. }
  267. else {
  268. if ( (tbtemp = gmtime(&tmptm1)) == NULL )
  269. goto err_mktime;
  270. }
  271. /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
  272. /***** for local time if requested *****/
  273. *tb = *tbtemp;
  274. return (time_t)tmptm1;
  275. err_mktime:
  276. /*
  277. * All errors come to here
  278. */
  279. return (time_t)(-1);
  280. }