(fix_submap_inheritance, get_keyelt, store_in_keymap,
[bpt/emacs.git] / src / mktime.c
CommitLineData
067cc4dc 1/* Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
98f1928d
PE
2 Contributed by Paul Eggert (eggert@twinsun.com).
3
89752145
PE
4 NOTE: The canonical source of this file is maintained with the GNU C Library.
5 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
98f1928d 6
89752145
PE
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
98f1928d 11
89752145
PE
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
98f1928d 16
89752145
PE
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA. */
98f1928d
PE
21
22/* Define this to have a standalone program to test this implementation of
23 mktime. */
24/* #define DEBUG 1 */
25
26#ifdef HAVE_CONFIG_H
6385ec2b 27# include <config.h>
98f1928d
PE
28#endif
29
067cc4dc 30/* Some systems need this in order to declare localtime_r properly. */
6beba8e0
UD
31#ifndef _REENTRANT
32# define _REENTRANT 1
33#endif
34
98f1928d
PE
35#ifdef _LIBC
36# define HAVE_LIMITS_H 1
37# define HAVE_LOCALTIME_R 1
38# define STDC_HEADERS 1
39#endif
40
41/* Assume that leap seconds are possible, unless told otherwise.
42 If the host has a `zic' command with a `-L leapsecondfilename' option,
43 then it supports leap seconds; otherwise it probably doesn't. */
44#ifndef LEAP_SECONDS_POSSIBLE
6385ec2b 45# define LEAP_SECONDS_POSSIBLE 1
98f1928d
PE
46#endif
47
48#include <sys/types.h> /* Some systems define `time_t' here. */
49#include <time.h>
50
51#if HAVE_LIMITS_H
6385ec2b 52# include <limits.h>
98f1928d
PE
53#endif
54
55#if DEBUG
6385ec2b
PE
56# include <stdio.h>
57# if STDC_HEADERS
58# include <stdlib.h>
59# endif
98f1928d 60/* Make it work even if the system's libc has its own mktime routine. */
6385ec2b 61# define mktime my_mktime
98f1928d
PE
62#endif /* DEBUG */
63
64#ifndef __P
6385ec2b
PE
65# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
66# define __P(args) args
67# else
68# define __P(args) ()
69# endif /* GCC. */
98f1928d
PE
70#endif /* Not __P. */
71
72#ifndef CHAR_BIT
6385ec2b 73# define CHAR_BIT 8
98f1928d
PE
74#endif
75
067cc4dc
UD
76/* The extra casts work around common compiler bugs. */
77#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
78/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
79 It is necessary at least when t == time_t. */
80#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
81 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
82#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t))
83
98f1928d 84#ifndef INT_MIN
067cc4dc 85# define INT_MIN TYPE_MINIMUM (int)
98f1928d
PE
86#endif
87#ifndef INT_MAX
067cc4dc 88# define INT_MAX TYPE_MAXIMUM (int)
98f1928d
PE
89#endif
90
91#ifndef TIME_T_MIN
067cc4dc 92# define TIME_T_MIN TYPE_MINIMUM (time_t)
98f1928d
PE
93#endif
94#ifndef TIME_T_MAX
067cc4dc 95# define TIME_T_MAX TYPE_MAXIMUM (time_t)
98f1928d
PE
96#endif
97
98#define TM_YEAR_BASE 1900
99#define EPOCH_YEAR 1970
100
101#ifndef __isleap
102/* Nonzero if YEAR is a leap year (every 4 years,
103 except every 100th isn't, and every 400th is). */
6385ec2b 104# define __isleap(year) \
98f1928d
PE
105 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
106#endif
107
108/* How many days come before each month (0-12). */
109const 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 };
116
649e97a3
UD
117static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
118 struct tm *)),
119 time_t *, struct tm *));
98f1928d
PE
120static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
121time_t __mktime_internal __P ((struct tm *,
122 struct tm *(*) (const time_t *, struct tm *),
123 time_t *));
124
125
126#ifdef _LIBC
6385ec2b 127# define localtime_r __localtime_r
98f1928d 128#else
6385ec2b 129# if ! HAVE_LOCALTIME_R && ! defined localtime_r
98f1928d 130/* Approximate localtime_r as best we can in its absence. */
6385ec2b 131# define localtime_r my_mktime_localtime_r
98f1928d
PE
132static struct tm *localtime_r __P ((const time_t *, struct tm *));
133static struct tm *
134localtime_r (t, tp)
135 const time_t *t;
136 struct tm *tp;
137{
138 struct tm *l = localtime (t);
139 if (! l)
140 return 0;
141 *tp = *l;
142 return tp;
143}
6385ec2b 144# endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
98f1928d
PE
145#endif /* ! _LIBC */
146
147
148/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
149 measured in seconds, ignoring leap seconds.
150 YEAR uses the same numbering as TM->tm_year.
151 All values are in range, except possibly YEAR.
649e97a3 152 If TP is null, return a nonzero value.
98f1928d
PE
153 If overflow occurs, yield the low order bits of the correct answer. */
154static time_t
155ydhms_tm_diff (year, yday, hour, min, sec, tp)
156 int year, yday, hour, min, sec;
157 const struct tm *tp;
158{
649e97a3
UD
159 if (!tp)
160 return 1;
161 else
162 {
163 /* Compute intervening leap days correctly even if year is negative.
164 Take care to avoid int overflow. time_t overflow is OK, since
165 only the low order bits of the correct time_t answer are needed.
166 Don't convert to time_t until after all divisions are done, since
167 time_t might be unsigned. */
168 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
169 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
170 int a100 = a4 / 25 - (a4 % 25 < 0);
171 int b100 = b4 / 25 - (b4 % 25 < 0);
172 int a400 = a100 >> 2;
173 int b400 = b100 >> 2;
174 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
175 time_t years = year - (time_t) tp->tm_year;
176 time_t days = (365 * years + intervening_leap_days
177 + (yday - tp->tm_yday));
178 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
179 + (min - tp->tm_min))
180 + (sec - tp->tm_sec));
181 }
98f1928d
PE
182}
183
184
185static time_t localtime_offset;
186
187/* Convert *TP to a time_t value. */
188time_t
189mktime (tp)
190 struct tm *tp;
191{
192#ifdef _LIBC
193 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
194 time zone names contained in the external variable `tzname' shall
195 be set as if the tzset() function had been called. */
196 __tzset ();
197#endif
198
199 return __mktime_internal (tp, localtime_r, &localtime_offset);
200}
201
649e97a3
UD
202/* Use CONVERT to convert *T to a broken down time in *TP.
203 If *T is out of range for conversion, adjust it so that
204 it is the nearest in-range value and then convert that. */
205static struct tm *
206ranged_convert (convert, t, tp)
207 struct tm *(*convert) __P ((const time_t *, struct tm *));
208 time_t *t;
209 struct tm *tp;
210{
211 struct tm *r;
212
213 if (! (r = (*convert) (t, tp)) && *t)
214 {
215 time_t bad = *t;
216 time_t ok = 0;
217 struct tm tm;
218
219 /* BAD is a known unconvertible time_t, and OK is a known good one.
220 Use binary search to narrow the range between BAD and OK until
221 they differ by 1. */
222 while (bad != ok + (bad < 0 ? -1 : 1))
223 {
224 time_t mid = *t = (bad < 0
225 ? bad + ((ok - bad) >> 1)
226 : ok + ((bad - ok) >> 1));
227 if ((r = (*convert) (t, tp)))
228 {
229 tm = *r;
230 ok = mid;
231 }
232 else
233 bad = mid;
234 }
235
236 if (!r && ok)
237 {
238 /* The last conversion attempt failed;
239 revert to the most recent successful attempt. */
240 *t = ok;
241 *tp = tm;
242 r = tp;
243 }
244 }
245
246 return r;
247}
248
249
98f1928d
PE
250/* Convert *TP to a time_t value, inverting
251 the monotonic and mostly-unit-linear conversion function CONVERT.
252 Use *OFFSET to keep track of a guess at the offset of the result,
253 compared to what the result would be for UTC without leap seconds.
254 If *OFFSET's guess is correct, only one CONVERT call is needed. */
255time_t
256__mktime_internal (tp, convert, offset)
257 struct tm *tp;
258 struct tm *(*convert) __P ((const time_t *, struct tm *));
259 time_t *offset;
260{
261 time_t t, dt, t0;
262 struct tm tm;
263
264 /* The maximum number of probes (calls to CONVERT) should be enough
265 to handle any combinations of time zone rule changes, solar time,
4dab1e80 266 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts
98f1928d
PE
267 have them anyway. */
268 int remaining_probes = 4;
269
270 /* Time requested. Copy it in case CONVERT modifies *TP; this can
271 occur if TP is localtime's returned value and CONVERT is localtime. */
272 int sec = tp->tm_sec;
273 int min = tp->tm_min;
274 int hour = tp->tm_hour;
275 int mday = tp->tm_mday;
276 int mon = tp->tm_mon;
277 int year_requested = tp->tm_year;
278 int isdst = tp->tm_isdst;
279
280 /* Ensure that mon is in range, and set year accordingly. */
281 int mon_remainder = mon % 12;
282 int negative_mon_remainder = mon_remainder < 0;
283 int mon_years = mon / 12 - negative_mon_remainder;
284 int year = year_requested + mon_years;
285
286 /* The other values need not be in range:
287 the remaining code handles minor overflows correctly,
288 assuming int and time_t arithmetic wraps around.
289 Major overflows are caught at the end. */
290
291 /* Calculate day of year from year, month, and day of month.
292 The result need not be in range. */
293 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
294 [mon_remainder + 12 * negative_mon_remainder])
295 + mday - 1);
296
89752145 297 int sec_requested = sec;
98f1928d
PE
298#if LEAP_SECONDS_POSSIBLE
299 /* Handle out-of-range seconds specially,
300 since ydhms_tm_diff assumes every minute has 60 seconds. */
98f1928d
PE
301 if (sec < 0)
302 sec = 0;
303 if (59 < sec)
304 sec = 59;
305#endif
306
307 /* Invert CONVERT by probing. First assume the same offset as last time.
308 Then repeatedly use the error to improve the guess. */
309
310 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
311 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
312 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
313
314 for (t = t0 + *offset;
649e97a3
UD
315 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
316 ranged_convert (convert, &t, &tm)));
98f1928d
PE
317 t += dt)
318 if (--remaining_probes == 0)
319 return -1;
320
321 /* Check whether tm.tm_isdst has the requested value, if any. */
322 if (0 <= isdst && 0 <= tm.tm_isdst)
323 {
324 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
325 if (dst_diff)
326 {
327 /* Move two hours in the direction indicated by the disagreement,
328 probe some more, and switch to a new time if found.
329 The largest known fallback due to daylight savings is two hours:
330 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
331 time_t ot = t - 2 * 60 * 60 * dst_diff;
332 while (--remaining_probes != 0)
333 {
334 struct tm otm;
335 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
649e97a3 336 ranged_convert (convert, &ot, &otm))))
98f1928d
PE
337 {
338 t = ot;
339 tm = otm;
340 break;
341 }
342 if ((ot += dt) == t)
343 break; /* Avoid a redundant probe. */
344 }
345 }
346 }
347
348 *offset = t - t0;
349
350#if LEAP_SECONDS_POSSIBLE
351 if (sec_requested != tm.tm_sec)
352 {
353 /* Adjust time to reflect the tm_sec requested, not the normalized value.
354 Also, repair any damage from a false match due to a leap second. */
355 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
649e97a3
UD
356 if (! (*convert) (&t, &tm))
357 return -1;
98f1928d
PE
358 }
359#endif
360
361 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
362 {
363 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
364 so check for major overflows. A gross check suffices,
365 since if t has overflowed, it is off by a multiple of
366 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
367 the difference that is bounded by a small value. */
368
369 double dyear = (double) year_requested + mon_years - tm.tm_year;
370 double dday = 366 * dyear + mday;
371 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
372
067cc4dc
UD
373 /* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
374 correct results, ie., it erroneously gives a positive value
375 of 715827882. Setting a variable first then doing math on it
376 seems to work. (ghazi@caip.rutgers.edu) */
377
378 const time_t time_t_max = TIME_T_MAX;
379 const time_t time_t_min = TIME_T_MIN;
380
381 if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
98f1928d
PE
382 return -1;
383 }
384
385 *tp = tm;
386 return t;
387}
388
389#ifdef weak_alias
390weak_alias (mktime, timelocal)
391#endif
392\f
393#if DEBUG
394
395static int
396not_equal_tm (a, b)
397 struct tm *a;
398 struct tm *b;
399{
400 return ((a->tm_sec ^ b->tm_sec)
401 | (a->tm_min ^ b->tm_min)
402 | (a->tm_hour ^ b->tm_hour)
403 | (a->tm_mday ^ b->tm_mday)
404 | (a->tm_mon ^ b->tm_mon)
405 | (a->tm_year ^ b->tm_year)
406 | (a->tm_mday ^ b->tm_mday)
407 | (a->tm_yday ^ b->tm_yday)
408 | (a->tm_isdst ^ b->tm_isdst));
409}
410
411static void
412print_tm (tp)
413 struct tm *tp;
414{
649e97a3
UD
415 if (tp)
416 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
417 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
418 tp->tm_hour, tp->tm_min, tp->tm_sec,
419 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
420 else
421 printf ("0");
98f1928d
PE
422}
423
424static int
649e97a3 425check_result (tk, tmk, tl, lt)
98f1928d
PE
426 time_t tk;
427 struct tm tmk;
428 time_t tl;
649e97a3 429 struct tm *lt;
98f1928d 430{
649e97a3 431 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
98f1928d
PE
432 {
433 printf ("mktime (");
434 print_tm (&tmk);
435 printf (")\nyields (");
649e97a3 436 print_tm (lt);
98f1928d
PE
437 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
438 return 1;
439 }
440
441 return 0;
442}
443
444int
445main (argc, argv)
446 int argc;
447 char **argv;
448{
449 int status = 0;
450 struct tm tm, tmk, tml;
649e97a3 451 struct tm *lt;
98f1928d
PE
452 time_t tk, tl;
453 char trailer;
454
455 if ((argc == 3 || argc == 4)
456 && (sscanf (argv[1], "%d-%d-%d%c",
457 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
458 == 3)
459 && (sscanf (argv[2], "%d:%d:%d%c",
460 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
461 == 3))
462 {
463 tm.tm_year -= TM_YEAR_BASE;
464 tm.tm_mon--;
465 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
466 tmk = tm;
467 tl = mktime (&tmk);
649e97a3
UD
468 lt = localtime (&tl);
469 if (lt)
470 {
471 tml = *lt;
472 lt = &tml;
473 }
98f1928d
PE
474 printf ("mktime returns %ld == ", (long) tl);
475 print_tm (&tmk);
476 printf ("\n");
649e97a3 477 status = check_result (tl, tmk, tl, lt);
98f1928d
PE
478 }
479 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
480 {
481 time_t from = atol (argv[1]);
482 time_t by = atol (argv[2]);
483 time_t to = atol (argv[3]);
484
485 if (argc == 4)
486 for (tl = from; tl <= to; tl += by)
487 {
649e97a3
UD
488 lt = localtime (&tl);
489 if (lt)
490 {
491 tmk = tml = *lt;
492 tk = mktime (&tmk);
493 status |= check_result (tk, tmk, tl, tml);
494 }
495 else
496 {
497 printf ("localtime (%ld) yields 0\n", (long) tl);
498 status = 1;
499 }
98f1928d
PE
500 }
501 else
502 for (tl = from; tl <= to; tl += by)
503 {
504 /* Null benchmark. */
649e97a3
UD
505 lt = localtime (&tl);
506 if (lt)
507 {
508 tmk = tml = *lt;
509 tk = tl;
510 status |= check_result (tk, tmk, tl, tml);
511 }
512 else
513 {
514 printf ("localtime (%ld) yields 0\n", (long) tl);
515 status = 1;
516 }
98f1928d
PE
517 }
518 }
519 else
520 printf ("Usage:\
521\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
522\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
523\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
524 argv[0], argv[0], argv[0]);
525
526 return status;
527}
528
529#endif /* DEBUG */
530\f
531/*
532Local Variables:
649e97a3 533compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
98f1928d
PE
534End:
535*/