/contrib/ntp/libntp/mktime.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 303 lines · 190 code · 33 blank · 80 comment · 49 complexity · a97d4114ae0271994ad7c6bc7e475de4 MD5 · raw file

  1. /*
  2. * Copyright (c) 1987, 1989 Regents of the University of California.
  3. * All rights reserved.
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Arthur David Olson of the National Cancer Institute.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. All advertising materials mentioning features or use of this software
  17. * must display the following acknowledgement:
  18. * This product includes software developed by the University of
  19. * California, Berkeley and its contributors.
  20. * 4. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE. */
  35. /*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/
  36. /*
  37. * This implementation of mktime is lifted straight from the NetBSD (BSD 4.4)
  38. * version. I modified it slightly to divorce it from the internals of the
  39. * ctime library. Thus this version can't use details of the internal
  40. * timezone state file to figure out strange unnormalized struct tm values,
  41. * as might result from someone doing date math on the tm struct then passing
  42. * it to mktime.
  43. *
  44. * It just does as well as it can at normalizing the tm input, then does a
  45. * binary search of the time space using the system's localtime() function.
  46. *
  47. * The original binary search was defective in that it didn't consider the
  48. * setting of tm_isdst when comparing tm values, causing the search to be
  49. * flubbed for times near the dst/standard time changeover. The original
  50. * code seems to make up for this by grubbing through the timezone info
  51. * whenever the binary search barfed. Since I don't have that luxury in
  52. * portable code, I have to take care of tm_isdst in the comparison routine.
  53. * This requires knowing how many minutes offset dst is from standard time.
  54. *
  55. * So, if you live somewhere in the world where dst is not 60 minutes offset,
  56. * and your vendor doesn't supply mktime(), you'll have to edit this variable
  57. * by hand. Sorry about that.
  58. */
  59. #include "ntp_machine.h"
  60. #if !defined(HAVE_MKTIME) || !defined(HAVE_TIMEGM)
  61. #ifndef DSTMINUTES
  62. #define DSTMINUTES 60
  63. #endif
  64. #define FALSE 0
  65. #define TRUE 1
  66. /* some constants from tzfile.h */
  67. #define SECSPERMIN 60
  68. #define MINSPERHOUR 60
  69. #define HOURSPERDAY 24
  70. #define DAYSPERWEEK 7
  71. #define DAYSPERNYEAR 365
  72. #define DAYSPERLYEAR 366
  73. #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
  74. #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
  75. #define MONSPERYEAR 12
  76. #define TM_YEAR_BASE 1900
  77. #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
  78. static int mon_lengths[2][MONSPERYEAR] = {
  79. { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  80. { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  81. };
  82. static int year_lengths[2] = {
  83. DAYSPERNYEAR, DAYSPERLYEAR
  84. };
  85. /*
  86. ** Adapted from code provided by Robert Elz, who writes:
  87. ** The "best" way to do mktime I think is based on an idea of Bob
  88. ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  89. ** It does a binary search of the time_t space. Since time_t's are
  90. ** just 32 bits, its a max of 32 iterations (even at 64 bits it
  91. ** would still be very reasonable).
  92. */
  93. #ifndef WRONG
  94. #define WRONG (-1)
  95. #endif /* !defined WRONG */
  96. static void
  97. normalize(
  98. int * tensptr,
  99. int * unitsptr,
  100. int base
  101. )
  102. {
  103. if (*unitsptr >= base) {
  104. *tensptr += *unitsptr / base;
  105. *unitsptr %= base;
  106. } else if (*unitsptr < 0) {
  107. --*tensptr;
  108. *unitsptr += base;
  109. if (*unitsptr < 0) {
  110. *tensptr -= 1 + (-*unitsptr) / base;
  111. *unitsptr = base - (-*unitsptr) % base;
  112. }
  113. }
  114. }
  115. static struct tm *
  116. mkdst(
  117. struct tm * tmp
  118. )
  119. {
  120. /* jds */
  121. static struct tm tmbuf;
  122. tmbuf = *tmp;
  123. tmbuf.tm_isdst = 1;
  124. tmbuf.tm_min += DSTMINUTES;
  125. normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR);
  126. return &tmbuf;
  127. }
  128. static int
  129. tmcomp(
  130. register struct tm * atmp,
  131. register struct tm * btmp
  132. )
  133. {
  134. register int result;
  135. /* compare down to the same day */
  136. if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  137. (result = (atmp->tm_mon - btmp->tm_mon)) == 0)
  138. result = (atmp->tm_mday - btmp->tm_mday);
  139. if(result != 0)
  140. return result;
  141. /* get rid of one-sided dst bias */
  142. if(atmp->tm_isdst == 1 && !btmp->tm_isdst)
  143. btmp = mkdst(btmp);
  144. else if(btmp->tm_isdst == 1 && !atmp->tm_isdst)
  145. atmp = mkdst(atmp);
  146. /* compare the rest of the way */
  147. if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  148. (result = (atmp->tm_min - btmp->tm_min)) == 0)
  149. result = atmp->tm_sec - btmp->tm_sec;
  150. return result;
  151. }
  152. static time_t
  153. time2(
  154. struct tm * tmp,
  155. int * okayp,
  156. int usezn
  157. )
  158. {
  159. register int dir;
  160. register int bits;
  161. register int i;
  162. register int saved_seconds;
  163. time_t t;
  164. struct tm yourtm, mytm;
  165. *okayp = FALSE;
  166. yourtm = *tmp;
  167. if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
  168. normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
  169. normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
  170. normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
  171. normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
  172. while (yourtm.tm_mday <= 0) {
  173. --yourtm.tm_year;
  174. yourtm.tm_mday +=
  175. year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
  176. }
  177. for ( ; ; ) {
  178. i = mon_lengths[isleap(yourtm.tm_year +
  179. TM_YEAR_BASE)][yourtm.tm_mon];
  180. if (yourtm.tm_mday <= i)
  181. break;
  182. yourtm.tm_mday -= i;
  183. if (++yourtm.tm_mon >= MONSPERYEAR) {
  184. yourtm.tm_mon = 0;
  185. ++yourtm.tm_year;
  186. }
  187. }
  188. saved_seconds = yourtm.tm_sec;
  189. yourtm.tm_sec = 0;
  190. /*
  191. ** Calculate the number of magnitude bits in a time_t
  192. ** (this works regardless of whether time_t is
  193. ** signed or unsigned, though lint complains if unsigned).
  194. */
  195. for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  196. ;
  197. /*
  198. ** If time_t is signed, then 0 is the median value,
  199. ** if time_t is unsigned, then 1 << bits is median.
  200. */
  201. t = (t < 0) ? 0 : ((time_t) 1 << bits);
  202. for ( ; ; ) {
  203. if (usezn)
  204. mytm = *localtime(&t);
  205. else
  206. mytm = *gmtime(&t);
  207. dir = tmcomp(&mytm, &yourtm);
  208. if (dir != 0) {
  209. if (bits-- < 0)
  210. return WRONG;
  211. if (bits < 0)
  212. --t;
  213. else if (dir > 0)
  214. t -= (time_t) 1 << bits;
  215. else t += (time_t) 1 << bits;
  216. continue;
  217. }
  218. if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  219. break;
  220. return WRONG;
  221. }
  222. t += saved_seconds;
  223. if (usezn)
  224. *tmp = *localtime(&t);
  225. else
  226. *tmp = *gmtime(&t);
  227. *okayp = TRUE;
  228. return t;
  229. }
  230. #else
  231. int mktime_bs;
  232. #endif /* !HAVE_MKTIME || !HAVE_TIMEGM */
  233. #ifndef HAVE_MKTIME
  234. static time_t
  235. time1(
  236. struct tm * tmp
  237. )
  238. {
  239. register time_t t;
  240. int okay;
  241. if (tmp->tm_isdst > 1)
  242. tmp->tm_isdst = 1;
  243. t = time2(tmp, &okay, 1);
  244. if (okay || tmp->tm_isdst < 0)
  245. return t;
  246. return WRONG;
  247. }
  248. time_t
  249. mktime(
  250. struct tm * tmp
  251. )
  252. {
  253. return time1(tmp);
  254. }
  255. #endif /* !HAVE_MKTIME */
  256. #ifndef HAVE_TIMEGM
  257. time_t
  258. timegm(
  259. struct tm * tmp
  260. )
  261. {
  262. register time_t t;
  263. int okay;
  264. tmp->tm_isdst = 0;
  265. t = time2(tmp, &okay, 0);
  266. if (okay || tmp->tm_isdst < 0)
  267. return t;
  268. return WRONG;
  269. }
  270. #endif /* !HAVE_TIMEGM */