1 /* Copyright (C) 1993, 1994 Free Software Foundation, Inc.
2 Contributed by Noel Cragg (noel@cs.oberlin.edu).
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
26 #if defined (CONFIG_BROKETS)
27 /* We use <config.h> instead of "config.h" so that a compilation
28 using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
29 (which it would do because it found this file in $srcdir). */
36 #include <sys/types.h> /* Some systems define `time_t' here. */
41 /* Nonzero if YEAR is a leap year (every 4 years,
42 except every 100th isn't, and every 400th is). */
43 #define __isleap(year) \
44 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
48 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
49 #define __P(args) args
55 /* How many days are in each month. */
56 const unsigned short int __mon_lengths[2][12] =
59 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
61 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
65 static int times_through_search; /* This library routine should never
66 hang -- make sure we always return
67 when we're searching for a value */
69 /* After testing this, the maximum number of iterations that I had on
70 any number that I tried was 3! Not bad.
72 mktime converts a `struct tm' (broken-down local time) into a `time_t';
73 it is the opposite of localtime. It is possible to put the following
74 values out of range and have mktime compensate: tm_sec, tm_min, tm_hour,
75 tm_mday, tm_year. The other values in the structure are ignored. */
82 int debugging_enabled = 0;
84 /* Print the values in a `struct tm'. */
89 printf ("%d/%d/%d %d:%d:%d (%s) yday:%d f:%d o:%ld",
110 unsigned long int v1, v2;
115 #define doit(x, secs) \
116 v1 += t1->x * secs; \
117 v2 += t2->x * secs; \
122 else if (t1->x > t2->x) \
126 doit (tm_year, 31536000); /* Okay, not all years have 365 days. */
127 doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */
128 doit (tm_mday, 86400);
129 doit (tm_hour, 3600);
135 /* We should also make sure that the sign of DISTANCE is correct -- if
136 DIFF_FLAG is positive, the distance should be positive and vice versa. */
138 distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
140 distance = -distance;
142 if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
143 never hang if there's a problem with
146 distance = diff_flag;
149 /* We need this DIFF_FLAG business because it is forseeable that the
150 distance may be zero when, in actuality, the two structures are
151 different. This is usually the case when the dates are 366 days apart
152 and one of the years is a leap year. */
154 if (distance == 0 && diff_flag)
155 distance = 86400 * diff_flag;
161 /* Modified b-search -- make intelligent guesses as to where the time might
162 lie along the timeline, assuming that our target time lies a linear
163 distance (w/o considering time jumps of a particular region).
165 Assume that time does not fluctuate at all along the timeline -- e.g.,
166 assume that a day will always take 86400 seconds, etc. -- and come up
167 with a hypothetical value for the time_t representation of the struct tm
168 TARGET, in relation to the guess variable -- it should be pretty close! */
171 search (target, producer)
173 struct tm *(*producer) __P ((const time_t *));
179 times_through_search = 0;
185 times_through_search++;
187 guess_tm = (*producer) (&guess);
190 if (debugging_enabled)
192 printf ("guess %d == ", (int) guess);
198 /* Are we on the money? */
199 distance = dist_tm (target, guess_tm);
201 } while (distance != 0);
206 /* Since this function will call localtime many times (and the user might
207 be passing their `struct tm *' right from localtime, let's make a copy
208 for ourselves and run the search on the copy.
210 Also, we have to normalize *TIMEPTR because it's possible to call mktime
211 with values that are out of range for a specific item (like Feb 30th). */
213 _mktime_internal (timeptr, producer)
215 struct tm *(*producer) __P ((const time_t *));
217 struct tm private_mktime_struct_tm; /* Yes, users can get a ptr to this. */
221 me = &private_mktime_struct_tm;
225 #define normalize(foo,x,y,bar); \
226 while (me->foo < x) \
229 me->foo = (y - (x - me->foo)); \
231 while (me->foo > y) \
234 me->foo = (x + (me->foo - y)); \
237 normalize (tm_sec, 0, 59, tm_min);
238 normalize (tm_min, 0, 59, tm_hour);
239 normalize (tm_hour, 0, 23, tm_mday);
241 /* Do the month first, so day range can be found. */
242 normalize (tm_mon, 0, 11, tm_year);
243 normalize (tm_mday, 1,
244 __mon_lengths[__isleap (me->tm_year)][me->tm_mon],
247 /* Do the month again, because the day may have pushed it out of range. */
248 normalize (tm_mon, 0, 11, tm_year);
250 /* Do the day again, because the month may have changed the range. */
251 normalize (tm_mday, 1,
252 __mon_lengths[__isleap (me->tm_year)][me->tm_mon],
256 if (debugging_enabled)
258 printf ("After normalizing: ");
264 result = search (me, producer);
275 return _mktime_internal (timeptr, localtime);
292 printf ("starting long test...\n");
294 for (q = 10000000; q < 1000000000; q++)
296 struct tm *tm = localtime (&q);
297 if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
298 if (q != mktime (tm))
299 { printf ("failed for %ld\n", q); fflush (stdout); }
302 printf ("test finished\n");
309 printf ("wrong # of args\n");
313 debugging_enabled = 1; /* We want to see the info */
318 printf ("Time: %d %s\n", time, ctime ((time_t *) &time));
320 tmptr = localtime ((time_t *) &time);
321 printf ("localtime returns: ");
324 printf ("mktime: %d\n\n", (int) mktime (tmptr));
328 tmptr->tm_hour -= 20;
329 tmptr->tm_mday -= 20;
331 tmptr->tm_year -= 20;
332 tmptr->tm_gmtoff -= 20000; /* This has no effect! */
333 tmptr->tm_zone = NULL; /* Nor does this! */
334 tmptr->tm_isdst = -1;
336 printf ("changed ranges: ");
340 result_time = mktime (tmptr);
341 printf ("\nmktime: %d\n", result_time);