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.

277 lines
8.1 KiB

  1. /***
  2. *mktime64.c - Convert struct tm value to __time64_t value.
  3. *
  4. * Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines _mktime64() and _mkgmtime64(), routines to converts a time
  8. * value in a tm structure (possibly incomplete) into a __time64_t value,
  9. * then update (all) the structure fields with "normalized" values.
  10. *
  11. *Revision History:
  12. * 05-07-98 GJF Created, adapted from Win64 version of mktime.c
  13. * 05-17-99 PML Remove all Macintosh support.
  14. *
  15. *******************************************************************************/
  16. #include <cruntime.h>
  17. #include <stddef.h>
  18. #include <ctime.h>
  19. #include <time.h>
  20. #include <internal.h>
  21. /*
  22. * Core function for both _mktime64() and _mkgmtime64()
  23. */
  24. static __time64_t __cdecl _make__time64_t( struct tm *, int);
  25. /***
  26. *__time64_t _mktime64(tb) - Normalize user time block structure
  27. *
  28. *Purpose:
  29. * _mktime64 converts a time structure, passed in as an argument, into a
  30. * 64-bit calendar time value in internal format (__time64_t). It also
  31. * completes and updates the fields the of the passed in structure with
  32. * 'normalized' values. There are three practical uses for this routine:
  33. *
  34. * (1) Convert broken-down time to internal time format (__time64_t).
  35. * (2) To have _mktime64 fill in the tm_wday, tm_yday, or tm_isdst fields.
  36. * (3) To pass in a time structure with 'out of range' values for some
  37. * fields and have _mktime64 "normalize" them (e.g., pass in 1/35/87 and
  38. * get back 2/4/87).
  39. *Entry:
  40. * struct tm *tb - pointer to a tm time structure to convert and
  41. * normalize
  42. *
  43. *Exit:
  44. * If successful, _mktime64 returns the specified calender time encoded as
  45. * a __time64_t value. Otherwise, (__time64_t)(-1) is returned to indicate an
  46. * error.
  47. *
  48. *Exceptions:
  49. * None.
  50. *
  51. *******************************************************************************/
  52. __time64_t __cdecl _mktime64 (
  53. struct tm *tb
  54. )
  55. {
  56. return( _make__time64_t(tb, 1) );
  57. }
  58. /***
  59. *__time64_t _mkgmtime64(tb) - Convert broken down UTC time to __time64_t
  60. *
  61. *Purpose:
  62. * Convert a tm structure, passed in as an argument, containing a UTC
  63. * time value to 64-bit internal format (__time64_t). It also completes
  64. * and updates the fields the of the passed in structure with 'normalized'
  65. * values.
  66. *
  67. *Entry:
  68. * struct tm *tb - pointer to a tm time structure to convert and
  69. * normalize
  70. *
  71. *Exit:
  72. * If successful, _mkgmtime64 returns the calender time encoded as a
  73. * __time64_t value.
  74. * Otherwise, (__time64_t)(-1) is returned to indicate an error.
  75. *
  76. *Exceptions:
  77. * None.
  78. *
  79. *******************************************************************************/
  80. __time64_t __cdecl _mkgmtime64 (
  81. struct tm *tb
  82. )
  83. {
  84. return( _make__time64_t(tb, 0) );
  85. }
  86. /***
  87. *static __time64_t make_time_t(tb, ultflag) -
  88. *
  89. *Purpose:
  90. * Converts a struct tm value to a __time64_t value, then updates the
  91. * struct tm value. Either local time or UTC is supported, based on
  92. * ultflag. This is the routine that actually does the work for both
  93. * _mktime64() and _mkgmtime64().
  94. *
  95. *Entry:
  96. * struct tm *tb - pointer to a tm time structure to convert and
  97. * normalize
  98. * int ultflag - use local time flag. the tb structure is assumed
  99. * to represent a local date/time if ultflag > 0.
  100. * otherwise, UTC is assumed.
  101. *
  102. *Exit:
  103. * If successful, _mktime64 returns the specified calender time encoded
  104. * as a __time64_t value. Otherwise, (__time64_t)(-1) is returned to
  105. * indicate an error.
  106. *
  107. *Exceptions:
  108. * None.
  109. *
  110. *******************************************************************************/
  111. static __time64_t __cdecl _make__time64_t (
  112. struct tm *tb,
  113. int ultflag
  114. )
  115. {
  116. __time64_t tmptm1, tmptm2, tmptm3;
  117. struct tm *tbtemp;
  118. /*
  119. * First, make sure tm_year is reasonably close to being in range.
  120. */
  121. if ( ((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR64
  122. + 1) )
  123. goto err_mktime;
  124. /*
  125. * Adjust month value so it is in the range 0 - 11. This is because
  126. * we don't know how many days are in months 12, 13, 14, etc.
  127. */
  128. if ( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) {
  129. tmptm1 += (tb->tm_mon / 12);
  130. if ( (tb->tm_mon %= 12) < 0 ) {
  131. tb->tm_mon += 12;
  132. tmptm1--;
  133. }
  134. /*
  135. * Make sure year count is still in range.
  136. */
  137. if ( (tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR64 + 1) )
  138. goto err_mktime;
  139. }
  140. /***** HERE: tmptm1 holds number of elapsed years *****/
  141. /*
  142. * Calculate days elapsed minus one, in the given year, to the given
  143. * month. Check for leap year and adjust if necessary.
  144. */
  145. tmptm2 = _days[tb->tm_mon];
  146. if ( _IS_LEAP_YEAR(tmptm1) && (tb->tm_mon > 1) )
  147. tmptm2++;
  148. /*
  149. * Calculate elapsed days since base date (midnight, 1/1/70, UTC)
  150. *
  151. *
  152. * 365 days for each elapsed year since 1970, plus one more day for
  153. * each elapsed leap year. no danger of overflow because of the range
  154. * check (above) on tmptm1.
  155. */
  156. tmptm3 = (tmptm1 - _BASE_YEAR) * 365 + _ELAPSED_LEAP_YEARS(tmptm1);
  157. /*
  158. * elapsed days to current month (still no possible overflow)
  159. */
  160. tmptm3 += tmptm2;
  161. /*
  162. * elapsed days to current date.
  163. */
  164. tmptm1 = tmptm3 + (tmptm2 = (__time64_t)(tb->tm_mday));
  165. /***** HERE: tmptm1 holds number of elapsed days *****/
  166. /*
  167. * Calculate elapsed hours since base date
  168. */
  169. tmptm2 = tmptm1 * 24;
  170. tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_hour);
  171. /***** HERE: tmptm1 holds number of elapsed hours *****/
  172. /*
  173. * Calculate elapsed minutes since base date
  174. */
  175. tmptm2 = tmptm1 * 60;
  176. tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_min);
  177. /***** HERE: tmptm1 holds number of elapsed minutes *****/
  178. /*
  179. * Calculate elapsed seconds since base date
  180. */
  181. tmptm2 = tmptm1 * 60;
  182. tmptm1 = tmptm2 + (tmptm3 = (__time64_t)tb->tm_sec);
  183. /***** HERE: tmptm1 holds number of elapsed seconds *****/
  184. if ( ultflag ) {
  185. /*
  186. * Adjust for timezone. No need to check for overflow since
  187. * localtime() will check its arg value
  188. */
  189. #ifdef _POSIX_
  190. tzset();
  191. #else
  192. __tzset();
  193. #endif
  194. tmptm1 += _timezone;
  195. /*
  196. * Convert this second count back into a time block structure.
  197. * If localtime returns NULL, return an error.
  198. */
  199. if ( (tbtemp = _localtime64(&tmptm1)) == NULL )
  200. goto err_mktime;
  201. /*
  202. * Now must compensate for DST. The ANSI rules are to use the
  203. * passed-in tm_isdst flag if it is non-negative. Otherwise,
  204. * compute if DST applies. Recall that tbtemp has the time without
  205. * DST compensation, but has set tm_isdst correctly.
  206. */
  207. if ( (tb->tm_isdst > 0) || ((tb->tm_isdst < 0) &&
  208. (tbtemp->tm_isdst > 0)) ) {
  209. #ifdef _POSIX_
  210. tmptm1 -= _timezone;
  211. tmptm1 += _dstoffset;
  212. #else
  213. tmptm1 += _dstbias;
  214. #endif
  215. tbtemp = _localtime64(&tmptm1); /* reconvert, can't get NULL */
  216. }
  217. }
  218. else {
  219. if ( (tbtemp = _gmtime64(&tmptm1)) == NULL )
  220. goto err_mktime;
  221. }
  222. /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
  223. /***** for local time if requested *****/
  224. *tb = *tbtemp;
  225. return tmptm1;
  226. err_mktime:
  227. /*
  228. * All errors come to here
  229. */
  230. return (__time64_t)(-1);
  231. }