]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/mktime.c
[BZ #472]
[thirdparty/glibc.git] / time / mktime.c
CommitLineData
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>
15a33409 40#include <string.h> /* For string function builtin redirect. */
28f540f4 41
80fd7387 42#if DEBUG
9c2322bc 43# include <stdio.h>
85e07670 44# include <stdlib.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
1dfee75f
UD
49/* The extra casts work around common compiler bugs. */
50#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
51/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
52 It is necessary at least when t == time_t. */
53#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
54 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
36fafd9c 55#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
1dfee75f 56
80fd7387 57#ifndef TIME_T_MIN
1dfee75f 58# define TIME_T_MIN TYPE_MINIMUM (time_t)
28f540f4 59#endif
80fd7387 60#ifndef TIME_T_MAX
1dfee75f 61# define TIME_T_MAX TYPE_MAXIMUM (time_t)
28f540f4 62#endif
28f540f4 63
a28a0500
RM
64/* Verify a requirement at compile-time (unlike assert, which is runtime). */
65#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
66
67verify (time_t_is_integer, (time_t) 0.5 == 0);
68verify (twos_complement_arithmetic, -1 == ~1 + 1);
69verify (right_shift_propagates_sign, -1 >> 1 == -1);
70/* The code also assumes that signed integer overflow silently wraps
71 around, but this assumption can't be stated without causing a
72 diagnostic on some hosts. */
73
80fd7387 74#define EPOCH_YEAR 1970
a28a0500
RM
75#define TM_YEAR_BASE 1900
76verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
28f540f4 77
80fd7387
RM
78#ifndef __isleap
79/* Nonzero if YEAR is a leap year (every 4 years,
80 except every 100th isn't, and every 400th is). */
9c2322bc 81# define __isleap(year) \
80fd7387 82 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
28f540f4 83#endif
28f540f4 84
80fd7387 85/* How many days come before each month (0-12). */
8592ae92
UD
86#ifndef _LIBC
87static
88#endif
80fd7387
RM
89const unsigned short int __mon_yday[2][13] =
90 {
91 /* Normal years. */
92 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
93 /* Leap years. */
94 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
95 };
28f540f4 96
28f540f4 97
7683e140
RM
98#ifndef _LIBC
99/* Portable standalone applications should supply a "time_r.h" that
100 declares a POSIX-compliant localtime_r, for the benefit of older
101 implementations that lack localtime_r or have a nonstandard one.
102 See the gnulib time_r module for one way to implement this. */
103# include "time_r.h"
104# undef __localtime_r
105# define __localtime_r localtime_r
106#endif
c2216480 107
80fd7387
RM
108
109/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
110 measured in seconds, ignoring leap seconds.
111 YEAR uses the same numbering as TM->tm_year.
112 All values are in range, except possibly YEAR.
fe0ec73e 113 If TP is null, return a nonzero value.
80fd7387
RM
114 If overflow occurs, yield the low order bits of the correct answer. */
115static time_t
eda78eec
UD
116ydhms_tm_diff (int year, int yday, int hour, int min, int sec,
117 const struct tm *tp)
80fd7387 118{
fe0ec73e
UD
119 if (!tp)
120 return 1;
121 else
122 {
a28a0500
RM
123 verify (C99_integer_division, -1 / 2 == 0);
124
fe0ec73e
UD
125 /* Compute intervening leap days correctly even if year is negative.
126 Take care to avoid int overflow. time_t overflow is OK, since
127 only the low order bits of the correct time_t answer are needed.
128 Don't convert to time_t until after all divisions are done, since
129 time_t might be unsigned. */
130 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
131 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
132 int a100 = a4 / 25 - (a4 % 25 < 0);
133 int b100 = b4 / 25 - (b4 % 25 < 0);
134 int a400 = a100 >> 2;
135 int b400 = b100 >> 2;
136 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
137 time_t years = year - (time_t) tp->tm_year;
138 time_t days = (365 * years + intervening_leap_days
139 + (yday - tp->tm_yday));
140 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
141 + (min - tp->tm_min))
142 + (sec - tp->tm_sec));
143 }
80fd7387
RM
144}
145
fe0ec73e
UD
146/* Use CONVERT to convert *T to a broken down time in *TP.
147 If *T is out of range for conversion, adjust it so that
148 it is the nearest in-range value and then convert that. */
149static struct tm *
eda78eec
UD
150ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
151 time_t *t, struct tm *tp)
fe0ec73e
UD
152{
153 struct tm *r;
154
155 if (! (r = (*convert) (t, tp)) && *t)
156 {
157 time_t bad = *t;
158 time_t ok = 0;
159 struct tm tm;
160
161 /* BAD is a known unconvertible time_t, and OK is a known good one.
162 Use binary search to narrow the range between BAD and OK until
163 they differ by 1. */
164 while (bad != ok + (bad < 0 ? -1 : 1))
165 {
166 time_t mid = *t = (bad < 0
167 ? bad + ((ok - bad) >> 1)
168 : ok + ((bad - ok) >> 1));
169 if ((r = (*convert) (t, tp)))
170 {
171 tm = *r;
172 ok = mid;
173 }
174 else
175 bad = mid;
176 }
177
178 if (!r && ok)
179 {
180 /* The last conversion attempt failed;
181 revert to the most recent successful attempt. */
182 *t = ok;
183 *tp = tm;
184 r = tp;
185 }
186 }
187
188 return r;
189}
190
191
80fd7387
RM
192/* Convert *TP to a time_t value, inverting
193 the monotonic and mostly-unit-linear conversion function CONVERT.
194 Use *OFFSET to keep track of a guess at the offset of the result,
195 compared to what the result would be for UTC without leap seconds.
196 If *OFFSET's guess is correct, only one CONVERT call is needed. */
197time_t
eda78eec
UD
198__mktime_internal (struct tm *tp,
199 struct tm *(*convert) (const time_t *, struct tm *),
200 time_t *offset)
28f540f4 201{
25b3b17b 202 time_t t, dt, t0, t1, t2;
80fd7387
RM
203 struct tm tm;
204
205 /* The maximum number of probes (calls to CONVERT) should be enough
206 to handle any combinations of time zone rule changes, solar time,
25b3b17b
UD
207 leap seconds, and oscillations around a spring-forward gap.
208 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
209 int remaining_probes = 6;
80fd7387
RM
210
211 /* Time requested. Copy it in case CONVERT modifies *TP; this can
212 occur if TP is localtime's returned value and CONVERT is localtime. */
213 int sec = tp->tm_sec;
214 int min = tp->tm_min;
215 int hour = tp->tm_hour;
216 int mday = tp->tm_mday;
217 int mon = tp->tm_mon;
218 int year_requested = tp->tm_year;
219 int isdst = tp->tm_isdst;
220
b5ef404e
UD
221 /* 1 if the previous probe was DST. */
222 int dst2;
223
80fd7387
RM
224 /* Ensure that mon is in range, and set year accordingly. */
225 int mon_remainder = mon % 12;
226 int negative_mon_remainder = mon_remainder < 0;
227 int mon_years = mon / 12 - negative_mon_remainder;
228 int year = year_requested + mon_years;
229
8592ae92 230 /* The other values need not be in range:
80fd7387
RM
231 the remaining code handles minor overflows correctly,
232 assuming int and time_t arithmetic wraps around.
233 Major overflows are caught at the end. */
234
235 /* Calculate day of year from year, month, and day of month.
236 The result need not be in range. */
237 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
238 [mon_remainder + 12 * negative_mon_remainder])
239 + mday - 1);
240
9a0a462c 241 int sec_requested = sec;
55544141 242
78575a84
UD
243 /* Only years after 1970 are defined.
244 If year is 69, it might still be representable due to
245 timezone differences. */
246 if (year < 69)
55544141
UD
247 return -1;
248
80fd7387
RM
249#if LEAP_SECONDS_POSSIBLE
250 /* Handle out-of-range seconds specially,
251 since ydhms_tm_diff assumes every minute has 60 seconds. */
80fd7387
RM
252 if (sec < 0)
253 sec = 0;
254 if (59 < sec)
255 sec = 59;
256#endif
257
258 /* Invert CONVERT by probing. First assume the same offset as last time.
259 Then repeatedly use the error to improve the guess. */
260
261 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
262 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
263 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
28f540f4 264
b5ef404e 265 for (t = t1 = t2 = t0 + *offset, dst2 = 0;
fe0ec73e
UD
266 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
267 ranged_convert (convert, &t, &tm)));
b5ef404e 268 t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0)
25b3b17b 269 if (t == t1 && t != t2
b5ef404e
UD
270 && (tm.tm_isdst < 0
271 || (isdst < 0
272 ? dst2 <= (tm.tm_isdst != 0)
273 : (isdst != 0) != (tm.tm_isdst != 0))))
25b3b17b
UD
274 /* We can't possibly find a match, as we are oscillating
275 between two values. The requested time probably falls
276 within a spring-forward gap of size DT. Follow the common
277 practice in this case, which is to return a time that is DT
278 away from the requested time, preferring a time whose
b5ef404e
UD
279 tm_isdst differs from the requested value. (If no tm_isdst
280 was requested and only one of the two values has a nonzero
281 tm_isdst, prefer that value.) In practice, this is more
282 useful than returning -1. */
25b3b17b
UD
283 break;
284 else if (--remaining_probes == 0)
80fd7387
RM
285 return -1;
286
25b3b17b
UD
287 /* If we have a match, check whether tm.tm_isdst has the requested
288 value, if any. */
c0016081 289 if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
80fd7387 290 {
c0016081
UD
291 /* tm.tm_isdst has the wrong value. Look for a neighboring
292 time with the right value, and use its UTC offset.
293 Heuristic: probe the previous three calendar quarters (approximately),
294 looking for the desired isdst. This isn't perfect,
295 but it's good enough in practice. */
296 int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
297 int i;
298
299 /* If we're too close to the time_t limit, look in future quarters. */
300 if (t < TIME_T_MIN + 3 * quarter)
301 quarter = -quarter;
302
303 for (i = 1; i <= 3; i++)
28f540f4 304 {
c0016081
UD
305 time_t ot = t - i * quarter;
306 struct tm otm;
307 ranged_convert (convert, &ot, &otm);
308 if (otm.tm_isdst == isdst)
80fd7387 309 {
c0016081
UD
310 /* We found the desired tm_isdst.
311 Extrapolate back to the desired time. */
312 t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
313 ranged_convert (convert, &t, &tm);
314 break;
80fd7387 315 }
28f540f4 316 }
80fd7387 317 }
28f540f4 318
80fd7387
RM
319 *offset = t - t0;
320
321#if LEAP_SECONDS_POSSIBLE
322 if (sec_requested != tm.tm_sec)
323 {
324 /* Adjust time to reflect the tm_sec requested, not the normalized value.
325 Also, repair any damage from a false match due to a leap second. */
326 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
fe0ec73e
UD
327 if (! (*convert) (&t, &tm))
328 return -1;
28f540f4 329 }
80fd7387
RM
330#endif
331
332 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
28f540f4 333 {
80fd7387
RM
334 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
335 so check for major overflows. A gross check suffices,
336 since if t has overflowed, it is off by a multiple of
337 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
338 the difference that is bounded by a small value. */
339
340 double dyear = (double) year_requested + mon_years - tm.tm_year;
341 double dday = 366 * dyear + mday;
342 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
343
1dfee75f
UD
344 /* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
345 correct results, ie., it erroneously gives a positive value
346 of 715827882. Setting a variable first then doing math on it
347 seems to work. (ghazi@caip.rutgers.edu) */
348
349 const time_t time_t_max = TIME_T_MAX;
350 const time_t time_t_min = TIME_T_MIN;
351
352 if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
80fd7387 353 return -1;
28f540f4 354 }
80fd7387 355
78575a84
UD
356 if (year == 69)
357 {
358 /* If year was 69, need to check whether the time was representable
359 or not. */
360 if (t < 0 || t > 2 * 24 * 60 * 60)
361 return -1;
362 }
363
80fd7387
RM
364 *tp = tm;
365 return t;
366}
367
eda78eec
UD
368
369static time_t localtime_offset;
370
371/* Convert *TP to a time_t value. */
372time_t
85e07670 373mktime (struct tm *tp)
eda78eec
UD
374{
375#ifdef _LIBC
376 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
377 time zone names contained in the external variable `tzname' shall
378 be set as if the tzset() function had been called. */
379 __tzset ();
380#endif
381
7683e140 382 return __mktime_internal (tp, __localtime_r, &localtime_offset);
eda78eec
UD
383}
384
80fd7387
RM
385#ifdef weak_alias
386weak_alias (mktime, timelocal)
28f540f4 387#endif
c5598d47
RM
388
389#ifdef _LIBC
390libc_hidden_def (mktime)
391libc_hidden_weak (timelocal)
392#endif
80fd7387
RM
393\f
394#if DEBUG
28f540f4 395
80fd7387 396static int
85e07670 397not_equal_tm (const struct tm *a, const struct tm *b)
80fd7387
RM
398{
399 return ((a->tm_sec ^ b->tm_sec)
400 | (a->tm_min ^ b->tm_min)
401 | (a->tm_hour ^ b->tm_hour)
402 | (a->tm_mday ^ b->tm_mday)
403 | (a->tm_mon ^ b->tm_mon)
404 | (a->tm_year ^ b->tm_year)
405 | (a->tm_mday ^ b->tm_mday)
406 | (a->tm_yday ^ b->tm_yday)
407 | (a->tm_isdst ^ b->tm_isdst));
408}
28f540f4 409
80fd7387 410static void
85e07670 411print_tm (const struct tm *tp)
80fd7387 412{
fe0ec73e
UD
413 if (tp)
414 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
415 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
416 tp->tm_hour, tp->tm_min, tp->tm_sec,
417 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
418 else
419 printf ("0");
80fd7387 420}
28f540f4 421
80fd7387 422static int
85e07670 423check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
80fd7387 424{
fe0ec73e 425 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
80fd7387
RM
426 {
427 printf ("mktime (");
fe0ec73e 428 print_tm (lt);
85e07670
RM
429 printf (")\nyields (");
430 print_tm (&tmk);
431 printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
80fd7387
RM
432 return 1;
433 }
434
435 return 0;
436}
28f540f4 437
80fd7387 438int
85e07670 439main (int argc, char **argv)
80fd7387
RM
440{
441 int status = 0;
442 struct tm tm, tmk, tml;
fe0ec73e 443 struct tm *lt;
85e07670 444 time_t tk, tl, tl1;
80fd7387
RM
445 char trailer;
446
447 if ((argc == 3 || argc == 4)
448 && (sscanf (argv[1], "%d-%d-%d%c",
449 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
450 == 3)
451 && (sscanf (argv[2], "%d:%d:%d%c",
452 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
453 == 3))
454 {
455 tm.tm_year -= TM_YEAR_BASE;
456 tm.tm_mon--;
457 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
458 tmk = tm;
459 tl = mktime (&tmk);
fe0ec73e
UD
460 lt = localtime (&tl);
461 if (lt)
462 {
463 tml = *lt;
464 lt = &tml;
465 }
85e07670 466 printf ("mktime returns %ld == ", (long int) tl);
80fd7387
RM
467 print_tm (&tmk);
468 printf ("\n");
fe0ec73e 469 status = check_result (tl, tmk, tl, lt);
80fd7387
RM
470 }
471 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
472 {
473 time_t from = atol (argv[1]);
474 time_t by = atol (argv[2]);
475 time_t to = atol (argv[3]);
28f540f4 476
80fd7387 477 if (argc == 4)
85e07670 478 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
80fd7387 479 {
fe0ec73e
UD
480 lt = localtime (&tl);
481 if (lt)
482 {
483 tmk = tml = *lt;
484 tk = mktime (&tmk);
85e07670 485 status |= check_result (tk, tmk, tl, &tml);
fe0ec73e
UD
486 }
487 else
488 {
85e07670 489 printf ("localtime (%ld) yields 0\n", (long int) tl);
fe0ec73e
UD
490 status = 1;
491 }
85e07670
RM
492 tl1 = tl + by;
493 if ((tl1 < tl) != (by < 0))
494 break;
80fd7387
RM
495 }
496 else
85e07670 497 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
80fd7387
RM
498 {
499 /* Null benchmark. */
fe0ec73e
UD
500 lt = localtime (&tl);
501 if (lt)
502 {
503 tmk = tml = *lt;
504 tk = tl;
85e07670 505 status |= check_result (tk, tmk, tl, &tml);
fe0ec73e
UD
506 }
507 else
508 {
85e07670 509 printf ("localtime (%ld) yields 0\n", (long int) tl);
fe0ec73e
UD
510 status = 1;
511 }
85e07670
RM
512 tl1 = tl + by;
513 if ((tl1 < tl) != (by < 0))
514 break;
80fd7387
RM
515 }
516 }
517 else
518 printf ("Usage:\
519\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
520\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
521\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
522 argv[0], argv[0], argv[0]);
523
524 return status;
28f540f4 525}
28f540f4 526
80fd7387 527#endif /* DEBUG */
28f540f4
RM
528\f
529/*
530Local Variables:
a4dc5219 531compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
28f540f4
RM
532End:
533*/