1 /* $NetBSD: mktime.c,v 1.3 2003/12/04 16:23:37 drochner Exp $ */
4 * Copyright (c) 1987, 1989 Regents of the University of California.
7 * This code is derived from software contributed to Berkeley by
8 * Arthur David Olson of the National Cancer Institute.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 /*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/
41 * This implementation of mktime is lifted straight from the NetBSD (BSD 4.4)
42 * version. I modified it slightly to divorce it from the internals of the
43 * ctime library. Thus this version can't use details of the internal
44 * timezone state file to figure out strange unnormalized struct tm values,
45 * as might result from someone doing date math on the tm struct then passing
48 * It just does as well as it can at normalizing the tm input, then does a
49 * binary search of the time space using the system's localtime() function.
51 * The original binary search was defective in that it didn't consider the
52 * setting of tm_isdst when comparing tm values, causing the search to be
53 * flubbed for times near the dst/standard time changeover. The original
54 * code seems to make up for this by grubbing through the timezone info
55 * whenever the binary search barfed. Since I don't have that luxury in
56 * portable code, I have to take care of tm_isdst in the comparison routine.
57 * This requires knowing how many minutes offset dst is from standard time.
59 * So, if you live somewhere in the world where dst is not 60 minutes offset,
60 * and your vendor doesn't supply mktime(), you'll have to edit this variable
61 * by hand. Sorry about that.
64 #include "ntp_machine.h"
66 #if !defined(HAVE_MKTIME) || !defined(HAVE_TIMEGM)
75 /* some constants from tzfile.h */
77 #define MINSPERHOUR 60
78 #define HOURSPERDAY 24
80 #define DAYSPERNYEAR 365
81 #define DAYSPERLYEAR 366
82 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
83 #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
84 #define MONSPERYEAR 12
85 #define TM_YEAR_BASE 1900
86 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
88 static int mon_lengths
[2][MONSPERYEAR
] = {
89 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
90 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
93 static int year_lengths
[2] = {
94 DAYSPERNYEAR
, DAYSPERLYEAR
98 ** Adapted from code provided by Robert Elz, who writes:
99 ** The "best" way to do mktime I think is based on an idea of Bob
100 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
101 ** It does a binary search of the time_t space. Since time_t's are
102 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
103 ** would still be very reasonable).
108 #endif /* !defined WRONG */
117 if (*unitsptr
>= base
) {
118 *tensptr
+= *unitsptr
/ base
;
120 } else if (*unitsptr
< 0) {
124 *tensptr
-= 1 + (-*unitsptr
) / base
;
125 *unitsptr
= base
- (-*unitsptr
) % base
;
136 static struct tm tmbuf
;
140 tmbuf
.tm_min
+= DSTMINUTES
;
141 normalize(&tmbuf
.tm_hour
, &tmbuf
.tm_min
, MINSPERHOUR
);
147 register struct tm
* atmp
,
148 register struct tm
* btmp
153 /* compare down to the same day */
155 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
156 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0)
157 result
= (atmp
->tm_mday
- btmp
->tm_mday
);
162 /* get rid of one-sided dst bias */
164 if(atmp
->tm_isdst
== 1 && !btmp
->tm_isdst
)
166 else if(btmp
->tm_isdst
== 1 && !atmp
->tm_isdst
)
169 /* compare the rest of the way */
171 if ((result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
172 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
173 result
= atmp
->tm_sec
- btmp
->tm_sec
;
188 register int saved_seconds
;
190 struct tm yourtm
, mytm
;
194 if (yourtm
.tm_sec
>= SECSPERMIN
+ 2 || yourtm
.tm_sec
< 0)
195 normalize(&yourtm
.tm_min
, &yourtm
.tm_sec
, SECSPERMIN
);
196 normalize(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
);
197 normalize(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
);
198 normalize(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
);
199 while (yourtm
.tm_mday
<= 0) {
202 year_lengths
[isleap(yourtm
.tm_year
+ TM_YEAR_BASE
)];
205 i
= mon_lengths
[isleap(yourtm
.tm_year
+
206 TM_YEAR_BASE
)][yourtm
.tm_mon
];
207 if (yourtm
.tm_mday
<= i
)
210 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
215 saved_seconds
= yourtm
.tm_sec
;
218 ** Calculate the number of magnitude bits in a time_t
219 ** (this works regardless of whether time_t is
220 ** signed or unsigned, though lint complains if unsigned).
222 for (bits
= 0, t
= 1; t
> 0; ++bits
, t
<<= 1)
225 ** If time_t is signed, then 0 is the median value,
226 ** if time_t is unsigned, then 1 << bits is median.
228 t
= (t
< 0) ? 0 : ((time_t) 1 << bits
);
231 mytm
= *localtime(&t
);
234 dir
= tmcomp(&mytm
, &yourtm
);
241 t
-= (time_t) 1 << bits
;
242 else t
+= (time_t) 1 << bits
;
245 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
252 *tmp
= *localtime(&t
);
260 #endif /* !HAVE_MKTIME || !HAVE_TIMEGM */
271 if (tmp
->tm_isdst
> 1)
273 t
= time2(tmp
, &okay
, 1);
274 if (okay
|| tmp
->tm_isdst
< 0)
287 #endif /* !HAVE_MKTIME */
299 t
= time2(tmp
, &okay
, 0);
300 if (okay
|| tmp
->tm_isdst
< 0)
305 #endif /* !HAVE_TIMEGM */