Fix previous change. Use sed's y command instead.
[glibc/history.git] / time / mktime.c
blobc3c539526aa851cd108806143bc7d935c76ed2c4
1 /* Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
2 Contributed by Paul Eggert (eggert@twinsun.com).
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
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
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 Cambridge, MA 02139, USA. */
21 /* Define this to have a standalone program to test this implementation of
22 mktime. */
23 /* #define DEBUG 1 */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
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
33 #define LEAP_SECONDS_POSSIBLE 1
34 #endif
36 #include <sys/types.h> /* Some systems define `time_t' here. */
37 #include <time.h>
39 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
40 #include <limits.h>
41 #endif
43 #if DEBUG
44 #include <stdio.h>
45 #if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
46 #include <stdlib.h>
47 #endif
48 /* Make it work even if the system's libc has its own mktime routine. */
49 #define mktime my_mktime
50 #endif /* DEBUG */
52 #ifndef __P
53 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
54 #define __P(args) args
55 #else
56 #define __P(args) ()
57 #endif /* GCC. */
58 #endif /* Not __P. */
60 #ifndef CHAR_BIT
61 #define CHAR_BIT 8
62 #endif
64 #ifndef INT_MIN
65 #define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
66 #endif
67 #ifndef INT_MAX
68 #define INT_MAX (~0 - INT_MIN)
69 #endif
71 #ifndef TIME_T_MIN
72 #define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
73 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
74 #endif
75 #ifndef TIME_T_MAX
76 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
77 #endif
79 #define TM_YEAR_BASE 1900
80 #define EPOCH_YEAR 1970
82 #ifndef __isleap
83 /* Nonzero if YEAR is a leap year (every 4 years,
84 except every 100th isn't, and every 400th is). */
85 #define __isleap(year) \
86 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
87 #endif
89 /* How many days come before each month (0-12). */
90 const unsigned short int __mon_yday[2][13] =
92 /* Normal years. */
93 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
94 /* Leap years. */
95 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
98 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
99 time_t __mktime_internal __P ((struct tm *,
100 struct tm *(*) (const time_t *, struct tm *),
101 time_t *));
104 #if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
105 #ifdef _LIBC
106 #define localtime_r __localtime_r
107 #else
108 /* Approximate localtime_r as best we can in its absence. */
109 #define localtime_r my_localtime_r
110 static struct tm *localtime_r __P ((const time_t *, struct tm *));
111 static struct tm *
112 localtime_r (t, tp)
113 const time_t *t;
114 struct tm *tp;
116 struct tm *l = localtime (t);
117 if (! l)
118 return 0;
119 *tp = *l;
120 return tp;
122 #endif /* ! _LIBC */
123 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
126 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
127 measured in seconds, ignoring leap seconds.
128 YEAR uses the same numbering as TM->tm_year.
129 All values are in range, except possibly YEAR.
130 If overflow occurs, yield the low order bits of the correct answer. */
131 static time_t
132 ydhms_tm_diff (year, yday, hour, min, sec, tp)
133 int year, yday, hour, min, sec;
134 const struct tm *tp;
136 time_t ay = year + (time_t) (TM_YEAR_BASE - 1);
137 time_t by = tp->tm_year + (time_t) (TM_YEAR_BASE - 1);
138 time_t intervening_leap_days =
139 (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
140 time_t years = ay - by;
141 time_t days = (365 * years + intervening_leap_days
142 + (yday - tp->tm_yday));
143 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
144 + (min - tp->tm_min))
145 + (sec - tp->tm_sec));
149 static time_t localtime_offset;
151 /* Convert *TP to a time_t value. */
152 time_t
153 mktime (tp)
154 struct tm *tp;
156 return __mktime_internal (tp, localtime_r, &localtime_offset);
159 /* Convert *TP to a time_t value, inverting
160 the monotonic and mostly-unit-linear conversion function CONVERT.
161 Use *OFFSET to keep track of a guess at the offset of the result,
162 compared to what the result would be for UTC without leap seconds.
163 If *OFFSET's guess is correct, only one CONVERT call is needed. */
164 time_t
165 __mktime_internal (tp, convert, offset)
166 struct tm *tp;
167 struct tm *(*convert) __P ((const time_t *, struct tm *));
168 time_t *offset;
170 time_t t, dt, t0;
171 struct tm tm;
173 /* The maximum number of probes (calls to CONVERT) should be enough
174 to handle any combinations of time zone rule changes, solar time,
175 and leap seconds. Posix.1 prohibits leap seconds, but some hosts
176 have them anyway. */
177 int remaining_probes = 4;
179 /* Time requested. Copy it in case CONVERT modifies *TP; this can
180 occur if TP is localtime's returned value and CONVERT is localtime. */
181 int sec = tp->tm_sec;
182 int min = tp->tm_min;
183 int hour = tp->tm_hour;
184 int mday = tp->tm_mday;
185 int mon = tp->tm_mon;
186 int year_requested = tp->tm_year;
187 int isdst = tp->tm_isdst;
189 /* Ensure that mon is in range, and set year accordingly. */
190 int mon_remainder = mon % 12;
191 int negative_mon_remainder = mon_remainder < 0;
192 int mon_years = mon / 12 - negative_mon_remainder;
193 int year = year_requested + mon_years;
195 /* The other values need not be in range:
196 the remaining code handles minor overflows correctly,
197 assuming int and time_t arithmetic wraps around.
198 Major overflows are caught at the end. */
200 /* Calculate day of year from year, month, and day of month.
201 The result need not be in range. */
202 int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
203 [mon_remainder + 12 * negative_mon_remainder])
204 + mday - 1);
206 #if LEAP_SECONDS_POSSIBLE
207 /* Handle out-of-range seconds specially,
208 since ydhms_tm_diff assumes every minute has 60 seconds. */
209 int sec_requested = sec;
210 if (sec < 0)
211 sec = 0;
212 if (59 < sec)
213 sec = 59;
214 #endif
216 /* Invert CONVERT by probing. First assume the same offset as last time.
217 Then repeatedly use the error to improve the guess. */
219 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
220 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
221 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
223 for (t = t0 + *offset;
224 (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
225 t += dt)
226 if (--remaining_probes == 0)
227 return -1;
229 /* Check whether tm.tm_isdst has the requested value, if any. */
230 if (0 <= isdst && 0 <= tm.tm_isdst)
232 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
233 if (dst_diff)
235 /* Move two hours in the direction indicated by the disagreement,
236 probe some more, and switch to a new time if found.
237 The largest known fallback due to daylight savings is two hours:
238 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
239 time_t ot = t - 2 * 60 * 60 * dst_diff;
240 while (--remaining_probes != 0)
242 struct tm otm;
243 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
244 (*convert) (&ot, &otm))))
246 t = ot;
247 tm = otm;
248 break;
250 if ((ot += dt) == t)
251 break; /* Avoid a redundant probe. */
256 *offset = t - t0;
258 #if LEAP_SECONDS_POSSIBLE
259 if (sec_requested != tm.tm_sec)
261 /* Adjust time to reflect the tm_sec requested, not the normalized value.
262 Also, repair any damage from a false match due to a leap second. */
263 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
264 (*convert) (&t, &tm);
266 #endif
268 if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
270 /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
271 so check for major overflows. A gross check suffices,
272 since if t has overflowed, it is off by a multiple of
273 TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
274 the difference that is bounded by a small value. */
276 double dyear = (double) year_requested + mon_years - tm.tm_year;
277 double dday = 366 * dyear + mday;
278 double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
280 if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
281 return -1;
284 *tp = tm;
285 return t;
288 #ifdef weak_alias
289 weak_alias (mktime, timelocal)
290 #endif
292 #if DEBUG
294 static int
295 not_equal_tm (a, b)
296 struct tm *a;
297 struct tm *b;
299 return ((a->tm_sec ^ b->tm_sec)
300 | (a->tm_min ^ b->tm_min)
301 | (a->tm_hour ^ b->tm_hour)
302 | (a->tm_mday ^ b->tm_mday)
303 | (a->tm_mon ^ b->tm_mon)
304 | (a->tm_year ^ b->tm_year)
305 | (a->tm_mday ^ b->tm_mday)
306 | (a->tm_yday ^ b->tm_yday)
307 | (a->tm_isdst ^ b->tm_isdst));
310 static void
311 print_tm (tp)
312 struct tm *tp;
314 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
315 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
316 tp->tm_hour, tp->tm_min, tp->tm_sec,
317 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
320 static int
321 check_result (tk, tmk, tl, tml)
322 time_t tk;
323 struct tm tmk;
324 time_t tl;
325 struct tm tml;
327 if (tk != tl || not_equal_tm (&tmk, &tml))
329 printf ("mktime (");
330 print_tm (&tmk);
331 printf (")\nyields (");
332 print_tm (&tml);
333 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
334 return 1;
337 return 0;
341 main (argc, argv)
342 int argc;
343 char **argv;
345 int status = 0;
346 struct tm tm, tmk, tml;
347 time_t tk, tl;
348 char trailer;
350 if ((argc == 3 || argc == 4)
351 && (sscanf (argv[1], "%d-%d-%d%c",
352 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
353 == 3)
354 && (sscanf (argv[2], "%d:%d:%d%c",
355 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
356 == 3))
358 tm.tm_year -= TM_YEAR_BASE;
359 tm.tm_mon--;
360 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
361 tmk = tm;
362 tl = mktime (&tmk);
363 tml = *localtime (&tl);
364 printf ("mktime returns %ld == ", (long) tl);
365 print_tm (&tmk);
366 printf ("\n");
367 status = check_result (tl, tmk, tl, tml);
369 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
371 time_t from = atol (argv[1]);
372 time_t by = atol (argv[2]);
373 time_t to = atol (argv[3]);
375 if (argc == 4)
376 for (tl = from; tl <= to; tl += by)
378 tml = *localtime (&tl);
379 tmk = tml;
380 tk = mktime (&tmk);
381 status |= check_result (tk, tmk, tl, tml);
383 else
384 for (tl = from; tl <= to; tl += by)
386 /* Null benchmark. */
387 tml = *localtime (&tl);
388 tmk = tml;
389 tk = tl;
390 status |= check_result (tk, tmk, tl, tml);
393 else
394 printf ("Usage:\
395 \t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
396 \t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
397 \t%s FROM BY TO - # Do not test those values (for benchmark).\n",
398 argv[0], argv[0], argv[0]);
400 return status;
403 #endif /* DEBUG */
406 Local Variables:
407 compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
408 End: