]>
Commit | Line | Data |
---|---|---|
3f80a33b | 1 | /* Convert a `struct tm' to a time_t value. |
15a33409 | 2 | Copyright (C) 1993-1999, 2002, 2003, 2004 Free Software Foundation, Inc. |
5290baf0 | 3 | This file is part of the GNU C Library. |
80fd7387 | 4 | Contributed by Paul Eggert (eggert@twinsun.com). |
28f540f4 | 5 | |
5290baf0 | 6 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
28f540f4 | 10 | |
5290baf0 UD |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
28f540f4 | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
28f540f4 RM |
20 | |
21 | /* Define this to have a standalone program to test this implementation of | |
22 | mktime. */ | |
80fd7387 | 23 | /* #define DEBUG 1 */ |
28f540f4 RM |
24 | |
25 | #ifdef HAVE_CONFIG_H | |
9c2322bc | 26 | # include <config.h> |
28f540f4 RM |
27 | #endif |
28 | ||
80fd7387 RM |
29 | /* Assume that leap seconds are possible, unless told otherwise. |
30 | If the host has a `zic' command with a `-L leapsecondfilename' option, | |
31 | then it supports leap seconds; otherwise it probably doesn't. */ | |
32 | #ifndef LEAP_SECONDS_POSSIBLE | |
9c2322bc | 33 | # define LEAP_SECONDS_POSSIBLE 1 |
80fd7387 RM |
34 | #endif |
35 | ||
28f540f4 RM |
36 | #include <sys/types.h> /* Some systems define `time_t' here. */ |
37 | #include <time.h> | |
38 | ||
85e07670 | 39 | #include <limits.h> |
28f540f4 | 40 | |
80fd7387 | 41 | #if DEBUG |
9c2322bc | 42 | # include <stdio.h> |
85e07670 | 43 | # include <stdlib.h> |
347a6c2d | 44 | # include <string.h> |
80fd7387 | 45 | /* Make it work even if the system's libc has its own mktime routine. */ |
9c2322bc | 46 | # define mktime my_mktime |
80fd7387 | 47 | #endif /* DEBUG */ |
28f540f4 | 48 | |
1c67fabd RM |
49 | /* Shift A right by B bits portably, by dividing A by 2**B and |
50 | truncating towards minus infinity. A and B should be free of side | |
51 | effects, and B should be in the range 0 <= B <= INT_BITS - 2, where | |
52 | INT_BITS is the number of useful bits in an int. GNU code can | |
53 | assume that INT_BITS is at least 32. | |
54 | ||
55 | ISO C99 says that A >> B is implementation-defined if A < 0. Some | |
56 | implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift | |
57 | right in the usual way when A < 0, so SHR falls back on division if | |
58 | ordinary A >> B doesn't seem to be the usual signed shift. */ | |
59 | #define SHR(a, b) \ | |
60 | (-1 >> 1 == -1 \ | |
61 | ? (a) >> (b) \ | |
62 | : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0)) | |
63 | ||
1dfee75f UD |
64 | /* The extra casts work around common compiler bugs. */ |
65 | #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) | |
66 | /* The outer cast is needed to work around a bug in Cray C 5.0.3.0. | |
67 | It is necessary at least when t == time_t. */ | |
68 | #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ | |
69 | ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) | |
36fafd9c | 70 | #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) |
1dfee75f | 71 | |
80fd7387 | 72 | #ifndef TIME_T_MIN |
1dfee75f | 73 | # define TIME_T_MIN TYPE_MINIMUM (time_t) |
28f540f4 | 74 | #endif |
80fd7387 | 75 | #ifndef TIME_T_MAX |
1dfee75f | 76 | # define TIME_T_MAX TYPE_MAXIMUM (time_t) |
28f540f4 | 77 | #endif |
1c67fabd | 78 | #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1) |
28f540f4 | 79 | |
a28a0500 RM |
80 | /* Verify a requirement at compile-time (unlike assert, which is runtime). */ |
81 | #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; } | |
82 | ||
83 | verify (time_t_is_integer, (time_t) 0.5 == 0); | |
84 | verify (twos_complement_arithmetic, -1 == ~1 + 1); | |
a28a0500 RM |
85 | /* The code also assumes that signed integer overflow silently wraps |
86 | around, but this assumption can't be stated without causing a | |
87 | diagnostic on some hosts. */ | |
88 | ||
80fd7387 | 89 | #define EPOCH_YEAR 1970 |
a28a0500 RM |
90 | #define TM_YEAR_BASE 1900 |
91 | verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0); | |
28f540f4 | 92 | |
72035294 RM |
93 | /* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */ |
94 | static inline int | |
030d3715 | 95 | leapyear (long int year) |
72035294 RM |
96 | { |
97 | /* Don't add YEAR to TM_YEAR_BASE, as that might overflow. | |
98 | Also, work even if YEAR is negative. */ | |
99 | return | |
100 | ((year & 3) == 0 | |
101 | && (year % 100 != 0 | |
102 | || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3))); | |
103 | } | |
28f540f4 | 104 | |
80fd7387 | 105 | /* How many days come before each month (0-12). */ |
8592ae92 UD |
106 | #ifndef _LIBC |
107 | static | |
108 | #endif | |
80fd7387 RM |
109 | const unsigned short int __mon_yday[2][13] = |
110 | { | |
111 | /* Normal years. */ | |
112 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | |
113 | /* Leap years. */ | |
114 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | |
115 | }; | |
28f540f4 | 116 | |
28f540f4 | 117 | |
7683e140 RM |
118 | #ifndef _LIBC |
119 | /* Portable standalone applications should supply a "time_r.h" that | |
120 | declares a POSIX-compliant localtime_r, for the benefit of older | |
121 | implementations that lack localtime_r or have a nonstandard one. | |
122 | See the gnulib time_r module for one way to implement this. */ | |
123 | # include "time_r.h" | |
124 | # undef __localtime_r | |
125 | # define __localtime_r localtime_r | |
743c00e3 | 126 | # define __mktime_internal mktime_internal |
7683e140 | 127 | #endif |
c2216480 | 128 | |
e507cc56 RM |
129 | /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) - |
130 | (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks | |
131 | were not adjusted between the time stamps. | |
80fd7387 | 132 | |
e507cc56 RM |
133 | The YEAR values uses the same numbering as TP->tm_year. Values |
134 | need not be in the usual range. However, YEAR1 must not be less | |
135 | than 2 * INT_MIN or greater than 2 * INT_MAX. | |
136 | ||
137 | The result may overflow. It is the caller's responsibility to | |
138 | detect overflow. */ | |
139 | ||
140 | static inline time_t | |
141 | ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1, | |
142 | int year0, int yday0, int hour0, int min0, int sec0) | |
143 | { | |
144 | verify (C99_integer_division, -1 / 2 == 0); | |
145 | verify (long_int_year_and_yday_are_wide_enough, | |
146 | INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX); | |
147 | ||
148 | /* Compute intervening leap days correctly even if year is negative. | |
149 | Take care to avoid integer overflow here. */ | |
1c67fabd RM |
150 | int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3); |
151 | int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3); | |
e507cc56 RM |
152 | int a100 = a4 / 25 - (a4 % 25 < 0); |
153 | int b100 = b4 / 25 - (b4 % 25 < 0); | |
1c67fabd RM |
154 | int a400 = SHR (a100, 2); |
155 | int b400 = SHR (b100, 2); | |
e507cc56 RM |
156 | int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); |
157 | ||
158 | /* Compute the desired time in time_t precision. Overflow might | |
159 | occur here. */ | |
160 | time_t tyear1 = year1; | |
161 | time_t years = tyear1 - year0; | |
162 | time_t days = 365 * years + yday1 - yday0 + intervening_leap_days; | |
163 | time_t hours = 24 * days + hour1 - hour0; | |
164 | time_t minutes = 60 * hours + min1 - min0; | |
165 | time_t seconds = 60 * minutes + sec1 - sec0; | |
166 | return seconds; | |
167 | } | |
168 | ||
169 | ||
170 | /* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC), | |
171 | assuming that *T corresponds to *TP and that no clock adjustments | |
172 | occurred between *TP and the desired time. | |
173 | If TP is null, return a value not equal to *T; this avoids false matches. | |
174 | If overflow occurs, yield the minimal or maximal value, except do not | |
175 | yield a value equal to *T. */ | |
80fd7387 | 176 | static time_t |
e507cc56 RM |
177 | guess_time_tm (long int year, long int yday, int hour, int min, int sec, |
178 | const time_t *t, const struct tm *tp) | |
80fd7387 | 179 | { |
e507cc56 | 180 | if (tp) |
fe0ec73e | 181 | { |
e507cc56 RM |
182 | time_t d = ydhms_diff (year, yday, hour, min, sec, |
183 | tp->tm_year, tp->tm_yday, | |
184 | tp->tm_hour, tp->tm_min, tp->tm_sec); | |
185 | time_t t1 = *t + d; | |
186 | if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d)) | |
187 | return t1; | |
fe0ec73e | 188 | } |
e507cc56 RM |
189 | |
190 | /* Overflow occurred one way or another. Return the nearest result | |
191 | that is actually in range, except don't report a zero difference | |
192 | if the actual difference is nonzero, as that would cause a false | |
193 | match. */ | |
194 | return (*t < TIME_T_MIDPOINT | |
195 | ? TIME_T_MIN + (*t == TIME_T_MIN) | |
196 | : TIME_T_MAX - (*t == TIME_T_MAX)); | |
80fd7387 RM |
197 | } |
198 | ||
fe0ec73e UD |
199 | /* Use CONVERT to convert *T to a broken down time in *TP. |
200 | If *T is out of range for conversion, adjust it so that | |
201 | it is the nearest in-range value and then convert that. */ | |
202 | static struct tm * | |
eda78eec UD |
203 | ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), |
204 | time_t *t, struct tm *tp) | |
fe0ec73e UD |
205 | { |
206 | struct tm *r; | |
207 | ||
208 | if (! (r = (*convert) (t, tp)) && *t) | |
209 | { | |
210 | time_t bad = *t; | |
211 | time_t ok = 0; | |
212 | struct tm tm; | |
213 | ||
214 | /* BAD is a known unconvertible time_t, and OK is a known good one. | |
215 | Use binary search to narrow the range between BAD and OK until | |
216 | they differ by 1. */ | |
217 | while (bad != ok + (bad < 0 ? -1 : 1)) | |
218 | { | |
219 | time_t mid = *t = (bad < 0 | |
220 | ? bad + ((ok - bad) >> 1) | |
221 | : ok + ((bad - ok) >> 1)); | |
222 | if ((r = (*convert) (t, tp))) | |
223 | { | |
224 | tm = *r; | |
225 | ok = mid; | |
226 | } | |
227 | else | |
228 | bad = mid; | |
229 | } | |
230 | ||
231 | if (!r && ok) | |
232 | { | |
233 | /* The last conversion attempt failed; | |
234 | revert to the most recent successful attempt. */ | |
235 | *t = ok; | |
236 | *tp = tm; | |
237 | r = tp; | |
238 | } | |
239 | } | |
240 | ||
241 | return r; | |
242 | } | |
243 | ||
244 | ||
80fd7387 RM |
245 | /* Convert *TP to a time_t value, inverting |
246 | the monotonic and mostly-unit-linear conversion function CONVERT. | |
247 | Use *OFFSET to keep track of a guess at the offset of the result, | |
248 | compared to what the result would be for UTC without leap seconds. | |
e507cc56 RM |
249 | If *OFFSET's guess is correct, only one CONVERT call is needed. |
250 | This function is external because it is used also by timegm.c. */ | |
80fd7387 | 251 | time_t |
eda78eec UD |
252 | __mktime_internal (struct tm *tp, |
253 | struct tm *(*convert) (const time_t *, struct tm *), | |
254 | time_t *offset) | |
28f540f4 | 255 | { |
e507cc56 | 256 | time_t t, gt, t0, t1, t2; |
80fd7387 RM |
257 | struct tm tm; |
258 | ||
259 | /* The maximum number of probes (calls to CONVERT) should be enough | |
260 | to handle any combinations of time zone rule changes, solar time, | |
25b3b17b UD |
261 | leap seconds, and oscillations around a spring-forward gap. |
262 | POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ | |
263 | int remaining_probes = 6; | |
80fd7387 RM |
264 | |
265 | /* Time requested. Copy it in case CONVERT modifies *TP; this can | |
266 | occur if TP is localtime's returned value and CONVERT is localtime. */ | |
267 | int sec = tp->tm_sec; | |
268 | int min = tp->tm_min; | |
269 | int hour = tp->tm_hour; | |
270 | int mday = tp->tm_mday; | |
271 | int mon = tp->tm_mon; | |
272 | int year_requested = tp->tm_year; | |
273 | int isdst = tp->tm_isdst; | |
274 | ||
b5ef404e UD |
275 | /* 1 if the previous probe was DST. */ |
276 | int dst2; | |
277 | ||
80fd7387 RM |
278 | /* Ensure that mon is in range, and set year accordingly. */ |
279 | int mon_remainder = mon % 12; | |
280 | int negative_mon_remainder = mon_remainder < 0; | |
281 | int mon_years = mon / 12 - negative_mon_remainder; | |
030d3715 RM |
282 | long int lyear_requested = year_requested; |
283 | long int year = lyear_requested + mon_years; | |
80fd7387 | 284 | |
8592ae92 | 285 | /* The other values need not be in range: |
80fd7387 RM |
286 | the remaining code handles minor overflows correctly, |
287 | assuming int and time_t arithmetic wraps around. | |
288 | Major overflows are caught at the end. */ | |
289 | ||
290 | /* Calculate day of year from year, month, and day of month. | |
291 | The result need not be in range. */ | |
e507cc56 RM |
292 | int mon_yday = ((__mon_yday[leapyear (year)] |
293 | [mon_remainder + 12 * negative_mon_remainder]) | |
294 | - 1); | |
295 | long int lmday = mday; | |
296 | long int yday = mon_yday + lmday; | |
297 | ||
298 | time_t guessed_offset = *offset; | |
80fd7387 | 299 | |
9a0a462c | 300 | int sec_requested = sec; |
55544141 | 301 | |
e507cc56 RM |
302 | if (LEAP_SECONDS_POSSIBLE) |
303 | { | |
304 | /* Handle out-of-range seconds specially, | |
305 | since ydhms_tm_diff assumes every minute has 60 seconds. */ | |
306 | if (sec < 0) | |
307 | sec = 0; | |
308 | if (59 < sec) | |
309 | sec = 59; | |
310 | } | |
311 | ||
312 | /* Invert CONVERT by probing. First assume the same offset as last | |
313 | time. */ | |
314 | ||
315 | t0 = ydhms_diff (year, yday, hour, min, sec, | |
316 | EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset); | |
80fd7387 | 317 | |
e507cc56 RM |
318 | if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3) |
319 | { | |
320 | /* time_t isn't large enough to rule out overflows, so check | |
321 | for major overflows. A gross check suffices, since if t0 | |
322 | has overflowed, it is off by a multiple of TIME_T_MAX - | |
323 | TIME_T_MIN + 1. So ignore any component of the difference | |
324 | that is bounded by a small value. */ | |
325 | ||
326 | /* Approximate log base 2 of the number of time units per | |
327 | biennium. A biennium is 2 years; use this unit instead of | |
328 | years to avoid integer overflow. For example, 2 average | |
329 | Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds, | |
330 | which is 63113904 seconds, and rint (log2 (63113904)) is | |
331 | 26. */ | |
332 | int ALOG2_SECONDS_PER_BIENNIUM = 26; | |
333 | int ALOG2_MINUTES_PER_BIENNIUM = 20; | |
334 | int ALOG2_HOURS_PER_BIENNIUM = 14; | |
335 | int ALOG2_DAYS_PER_BIENNIUM = 10; | |
336 | int LOG2_YEARS_PER_BIENNIUM = 1; | |
337 | ||
338 | int approx_requested_biennia = | |
1c67fabd RM |
339 | (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM) |
340 | - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM) | |
341 | + SHR (mday, ALOG2_DAYS_PER_BIENNIUM) | |
342 | + SHR (hour, ALOG2_HOURS_PER_BIENNIUM) | |
343 | + SHR (min, ALOG2_MINUTES_PER_BIENNIUM) | |
344 | + (LEAP_SECONDS_POSSIBLE | |
345 | ? 0 | |
346 | : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM))); | |
347 | ||
348 | int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM); | |
e507cc56 RM |
349 | int diff = approx_biennia - approx_requested_biennia; |
350 | int abs_diff = diff < 0 ? - diff : diff; | |
351 | ||
352 | /* IRIX 4.0.5 cc miscaculates TIME_T_MIN / 3: it erroneously | |
353 | gives a positive value of 715827882. Setting a variable | |
354 | first then doing math on it seems to work. | |
355 | (ghazi@caip.rutgers.edu) */ | |
356 | time_t time_t_max = TIME_T_MAX; | |
357 | time_t time_t_min = TIME_T_MIN; | |
358 | time_t overflow_threshold = | |
359 | (time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM; | |
360 | ||
361 | if (overflow_threshold < abs_diff) | |
362 | { | |
363 | /* Overflow occurred. Try repairing it; this might work if | |
364 | the time zone offset is enough to undo the overflow. */ | |
365 | time_t repaired_t0 = -1 - t0; | |
1c67fabd | 366 | approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM); |
e507cc56 RM |
367 | diff = approx_biennia - approx_requested_biennia; |
368 | abs_diff = diff < 0 ? - diff : diff; | |
369 | if (overflow_threshold < abs_diff) | |
370 | return -1; | |
371 | guessed_offset += repaired_t0 - t0; | |
372 | t0 = repaired_t0; | |
373 | } | |
374 | } | |
80fd7387 | 375 | |
e507cc56 | 376 | /* Repeatedly use the error to improve the guess. */ |
28f540f4 | 377 | |
e507cc56 RM |
378 | for (t = t1 = t2 = t0, dst2 = 0; |
379 | (gt = guess_time_tm (year, yday, hour, min, sec, &t, | |
380 | ranged_convert (convert, &t, &tm)), | |
381 | t != gt); | |
382 | t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0) | |
25b3b17b | 383 | if (t == t1 && t != t2 |
b5ef404e UD |
384 | && (tm.tm_isdst < 0 |
385 | || (isdst < 0 | |
386 | ? dst2 <= (tm.tm_isdst != 0) | |
387 | : (isdst != 0) != (tm.tm_isdst != 0)))) | |
25b3b17b UD |
388 | /* We can't possibly find a match, as we are oscillating |
389 | between two values. The requested time probably falls | |
e507cc56 RM |
390 | within a spring-forward gap of size GT - T. Follow the common |
391 | practice in this case, which is to return a time that is GT - T | |
25b3b17b | 392 | away from the requested time, preferring a time whose |
b5ef404e UD |
393 | tm_isdst differs from the requested value. (If no tm_isdst |
394 | was requested and only one of the two values has a nonzero | |
395 | tm_isdst, prefer that value.) In practice, this is more | |
396 | useful than returning -1. */ | |
e507cc56 | 397 | goto offset_found; |
25b3b17b | 398 | else if (--remaining_probes == 0) |
80fd7387 RM |
399 | return -1; |
400 | ||
e507cc56 | 401 | /* We have a match. Check whether tm.tm_isdst has the requested |
25b3b17b | 402 | value, if any. */ |
e507cc56 | 403 | if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst) |
80fd7387 | 404 | { |
c0016081 UD |
405 | /* tm.tm_isdst has the wrong value. Look for a neighboring |
406 | time with the right value, and use its UTC offset. | |
c0016081 | 407 | |
e507cc56 RM |
408 | Heuristic: probe the adjacent timestamps in both directions, |
409 | looking for the desired isdst. This should work for all real | |
410 | time zone histories in the tz database. */ | |
411 | ||
412 | /* Distance between probes when looking for a DST boundary. In | |
413 | tzdata2003a, the shortest period of DST is 601200 seconds | |
414 | (e.g., America/Recife starting 2000-10-08 01:00), and the | |
415 | shortest period of non-DST surrounded by DST is 694800 | |
416 | seconds (Africa/Tunis starting 1943-04-17 01:00). Use the | |
417 | minimum of these two values, so we don't miss these short | |
418 | periods when probing. */ | |
419 | int stride = 601200; | |
420 | ||
421 | /* The longest period of DST in tzdata2003a is 536454000 seconds | |
422 | (e.g., America/Jujuy starting 1946-10-01 01:00). The longest | |
423 | period of non-DST is much longer, but it makes no real sense | |
424 | to search for more than a year of non-DST, so use the DST | |
425 | max. */ | |
426 | int duration_max = 536454000; | |
427 | ||
428 | /* Search in both directions, so the maximum distance is half | |
429 | the duration; add the stride to avoid off-by-1 problems. */ | |
430 | int delta_bound = duration_max / 2 + stride; | |
431 | ||
432 | int delta, direction; | |
433 | ||
434 | for (delta = stride; delta < delta_bound; delta += stride) | |
435 | for (direction = -1; direction <= 1; direction += 2) | |
436 | { | |
437 | time_t ot = t + delta * direction; | |
438 | if ((ot < t) == (direction < 0)) | |
439 | { | |
440 | struct tm otm; | |
441 | ranged_convert (convert, &ot, &otm); | |
442 | if (otm.tm_isdst == isdst) | |
443 | { | |
444 | /* We found the desired tm_isdst. | |
445 | Extrapolate back to the desired time. */ | |
446 | t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm); | |
447 | ranged_convert (convert, &t, &tm); | |
448 | goto offset_found; | |
449 | } | |
450 | } | |
451 | } | |
80fd7387 | 452 | } |
28f540f4 | 453 | |
e507cc56 RM |
454 | offset_found: |
455 | *offset = guessed_offset + t - t0; | |
80fd7387 | 456 | |
e507cc56 | 457 | if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec) |
80fd7387 RM |
458 | { |
459 | /* Adjust time to reflect the tm_sec requested, not the normalized value. | |
460 | Also, repair any damage from a false match due to a leap second. */ | |
e507cc56 RM |
461 | int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec; |
462 | t1 = t + sec_requested; | |
463 | t2 = t1 + sec_adjustment; | |
464 | if (((t1 < t) != (sec_requested < 0)) | |
465 | | ((t2 < t1) != (sec_adjustment < 0)) | |
466 | | ! (*convert) (&t, &tm)) | |
78575a84 UD |
467 | return -1; |
468 | } | |
469 | ||
80fd7387 RM |
470 | *tp = tm; |
471 | return t; | |
472 | } | |
473 | ||
eda78eec | 474 | |
e507cc56 RM |
475 | /* FIXME: This should use a signed type wide enough to hold any UTC |
476 | offset in seconds. 'int' should be good enough for GNU code. We | |
477 | can't fix this unilaterally though, as other modules invoke | |
478 | __mktime_internal. */ | |
eda78eec UD |
479 | static time_t localtime_offset; |
480 | ||
481 | /* Convert *TP to a time_t value. */ | |
482 | time_t | |
85e07670 | 483 | mktime (struct tm *tp) |
eda78eec UD |
484 | { |
485 | #ifdef _LIBC | |
486 | /* POSIX.1 8.1.1 requires that whenever mktime() is called, the | |
487 | time zone names contained in the external variable `tzname' shall | |
488 | be set as if the tzset() function had been called. */ | |
489 | __tzset (); | |
490 | #endif | |
491 | ||
7683e140 | 492 | return __mktime_internal (tp, __localtime_r, &localtime_offset); |
eda78eec UD |
493 | } |
494 | ||
80fd7387 RM |
495 | #ifdef weak_alias |
496 | weak_alias (mktime, timelocal) | |
28f540f4 | 497 | #endif |
c5598d47 RM |
498 | |
499 | #ifdef _LIBC | |
500 | libc_hidden_def (mktime) | |
501 | libc_hidden_weak (timelocal) | |
502 | #endif | |
80fd7387 RM |
503 | \f |
504 | #if DEBUG | |
28f540f4 | 505 | |
80fd7387 | 506 | static int |
85e07670 | 507 | not_equal_tm (const struct tm *a, const struct tm *b) |
80fd7387 RM |
508 | { |
509 | return ((a->tm_sec ^ b->tm_sec) | |
510 | | (a->tm_min ^ b->tm_min) | |
511 | | (a->tm_hour ^ b->tm_hour) | |
512 | | (a->tm_mday ^ b->tm_mday) | |
513 | | (a->tm_mon ^ b->tm_mon) | |
514 | | (a->tm_year ^ b->tm_year) | |
80fd7387 RM |
515 | | (a->tm_yday ^ b->tm_yday) |
516 | | (a->tm_isdst ^ b->tm_isdst)); | |
517 | } | |
28f540f4 | 518 | |
80fd7387 | 519 | static void |
85e07670 | 520 | print_tm (const struct tm *tp) |
80fd7387 | 521 | { |
fe0ec73e UD |
522 | if (tp) |
523 | printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d", | |
524 | tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday, | |
525 | tp->tm_hour, tp->tm_min, tp->tm_sec, | |
526 | tp->tm_yday, tp->tm_wday, tp->tm_isdst); | |
527 | else | |
528 | printf ("0"); | |
80fd7387 | 529 | } |
28f540f4 | 530 | |
80fd7387 | 531 | static int |
85e07670 | 532 | check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt) |
80fd7387 | 533 | { |
fe0ec73e | 534 | if (tk != tl || !lt || not_equal_tm (&tmk, lt)) |
80fd7387 RM |
535 | { |
536 | printf ("mktime ("); | |
fe0ec73e | 537 | print_tm (lt); |
85e07670 RM |
538 | printf (")\nyields ("); |
539 | print_tm (&tmk); | |
540 | printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl); | |
80fd7387 RM |
541 | return 1; |
542 | } | |
543 | ||
544 | return 0; | |
545 | } | |
28f540f4 | 546 | |
80fd7387 | 547 | int |
85e07670 | 548 | main (int argc, char **argv) |
80fd7387 RM |
549 | { |
550 | int status = 0; | |
551 | struct tm tm, tmk, tml; | |
fe0ec73e | 552 | struct tm *lt; |
85e07670 | 553 | time_t tk, tl, tl1; |
80fd7387 RM |
554 | char trailer; |
555 | ||
556 | if ((argc == 3 || argc == 4) | |
557 | && (sscanf (argv[1], "%d-%d-%d%c", | |
558 | &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer) | |
559 | == 3) | |
560 | && (sscanf (argv[2], "%d:%d:%d%c", | |
561 | &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer) | |
562 | == 3)) | |
563 | { | |
564 | tm.tm_year -= TM_YEAR_BASE; | |
565 | tm.tm_mon--; | |
566 | tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]); | |
567 | tmk = tm; | |
568 | tl = mktime (&tmk); | |
fe0ec73e UD |
569 | lt = localtime (&tl); |
570 | if (lt) | |
571 | { | |
572 | tml = *lt; | |
573 | lt = &tml; | |
574 | } | |
85e07670 | 575 | printf ("mktime returns %ld == ", (long int) tl); |
80fd7387 RM |
576 | print_tm (&tmk); |
577 | printf ("\n"); | |
fe0ec73e | 578 | status = check_result (tl, tmk, tl, lt); |
80fd7387 RM |
579 | } |
580 | else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0)) | |
581 | { | |
582 | time_t from = atol (argv[1]); | |
583 | time_t by = atol (argv[2]); | |
584 | time_t to = atol (argv[3]); | |
28f540f4 | 585 | |
80fd7387 | 586 | if (argc == 4) |
85e07670 | 587 | for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1) |
80fd7387 | 588 | { |
fe0ec73e UD |
589 | lt = localtime (&tl); |
590 | if (lt) | |
591 | { | |
592 | tmk = tml = *lt; | |
593 | tk = mktime (&tmk); | |
85e07670 | 594 | status |= check_result (tk, tmk, tl, &tml); |
fe0ec73e UD |
595 | } |
596 | else | |
597 | { | |
85e07670 | 598 | printf ("localtime (%ld) yields 0\n", (long int) tl); |
fe0ec73e UD |
599 | status = 1; |
600 | } | |
85e07670 RM |
601 | tl1 = tl + by; |
602 | if ((tl1 < tl) != (by < 0)) | |
603 | break; | |
80fd7387 RM |
604 | } |
605 | else | |
85e07670 | 606 | for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1) |
80fd7387 RM |
607 | { |
608 | /* Null benchmark. */ | |
fe0ec73e UD |
609 | lt = localtime (&tl); |
610 | if (lt) | |
611 | { | |
612 | tmk = tml = *lt; | |
613 | tk = tl; | |
85e07670 | 614 | status |= check_result (tk, tmk, tl, &tml); |
fe0ec73e UD |
615 | } |
616 | else | |
617 | { | |
85e07670 | 618 | printf ("localtime (%ld) yields 0\n", (long int) tl); |
fe0ec73e UD |
619 | status = 1; |
620 | } | |
85e07670 RM |
621 | tl1 = tl + by; |
622 | if ((tl1 < tl) != (by < 0)) | |
623 | break; | |
80fd7387 RM |
624 | } |
625 | } | |
626 | else | |
627 | printf ("Usage:\ | |
628 | \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\ | |
629 | \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\ | |
630 | \t%s FROM BY TO - # Do not test those values (for benchmark).\n", | |
631 | argv[0], argv[0], argv[0]); | |
632 | ||
633 | return status; | |
28f540f4 | 634 | } |
28f540f4 | 635 | |
80fd7387 | 636 | #endif /* DEBUG */ |
28f540f4 RM |
637 | \f |
638 | /* | |
639 | Local Variables: | |
a4dc5219 | 640 | compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime" |
28f540f4 RM |
641 | End: |
642 | */ |