1 /* Copyright (C) 1993 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. */
25 #include <sys/types.h> /* Some systems define `time_t' here. */
30 /* Nonzero if YEAR is a leap year (every 4 years,
31 except every 100th isn't, and every 400th is). */
32 #define __isleap(year) \
33 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
37 /* How many days are in each month. */
38 const unsigned short int __mon_lengths[2][12] =
41 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
43 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
47 /* After testing this, the maximum number of iterations that I had on
48 any number that I tried was 3! Not bad.
50 mktime converts a `struct tm' (broken-down local time) into a `time_t';
51 it is the opposite of localtime. It is possible to put the following
52 values out of range and have mktime compensate: tm_sec, tm_min, tm_hour,
53 tm_mday, tm_year. The other values in the structure are ignored. */
57 int debugging_enabled = 0;
59 /* Print the values in a `struct tm'. */
64 printf ("%d/%d/%d %d:%d:%d (%s) yday:%d f:%d o:%ld",
84 unsigned long int v1, v2;
89 #define doit(x, secs) \
96 else if (t1->x > t2->x) \
100 doit (tm_year, 31536000); /* Okay, not all years have 365 days. */
101 doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */
102 doit (tm_mday, 86400);
103 doit (tm_hour, 3600);
111 /* We need this DIFF_FLAG business because it is forseeable that the
112 distance may be zero when, in actuality, the two structures are
113 different. This is usually the case when the dates are 366 days
114 apart and one of the years is a leap year. */
116 if (distance == 0 && diff_flag)
117 distance = 86400 * diff_flag;
123 /* Modified binary search -- make intelligent guesses as to where the time
124 might lie along the timeline, assuming that our target time lies a
125 linear distance (w/o considering time jumps of a particular region).
127 Assume that time does not fluctuate at all along the timeline -- e.g.,
128 assume that a day will always take 86400 seconds, etc. -- and come up
129 with a hypothetical value for the time_t representation of the struct tm
130 TARGET, in relation to the guess variable -- it should be pretty close! */
144 guess_tm = localtime (&guess);
147 if (debugging_enabled)
149 printf ("guess %d == ", guess);
155 /* Are we on the money? */
156 distance = dist_tm (target, guess_tm);
158 } while (distance != 0);
163 /* Since this function will call localtime many times (and the user might
164 be passing their `struct tm *' right from localtime, let's make a copy
165 for ourselves and run the search on the copy.
167 Also, we have to normalize the timeptr because it's possible to call mktime
168 with values that are out of range for a specific item (like 30th Feb). */
174 struct tm private_mktime_struct_tm; /* Yes, users can get a ptr to this. */
178 me = &private_mktime_struct_tm;
182 #define normalize(foo,x,y,bar); \
183 while (me->foo < x) \
186 me->foo = (y - (x - me->foo)); \
188 while (me->foo > y) \
191 me->foo = (x + (me->foo - y)); \
194 normalize (tm_sec, 0, 59, tm_min);
195 normalize (tm_min, 0, 59, tm_hour);
196 normalize (tm_hour, 0, 23, tm_mday);
198 /* Do the month first, so day range can be found. */
199 normalize (tm_mon, 0, 11, tm_year);
200 normalize (tm_mday, 1,
201 __mon_lengths[__isleap (me->tm_year)][me->tm_mon],
204 /* Do the month again, because the day may have pushed it out of range. */
205 normalize (tm_mon, 0, 11, tm_year);
207 /* Do day again, because month may have changed the range. */
208 normalize (tm_mday, 1,
209 __mon_lengths[__isleap (me->tm_year)][me->tm_mon],
213 if (debugging_enabled)
215 printf ("After normalizing: ");
221 result = search (me);
242 printf ("starting long test...\n");
244 for (q = 10000000; q < 1000000000; q++)
246 struct tm *tm = localtime (&q);
247 if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
248 if (q != my_mktime (tm))
249 { printf ("failed for %ld\n", q); fflush (stdout); }
252 printf ("test finished\n");
259 printf ("wrong # of args\n");
263 debugging_enabled = 1; /* we want to see the info */
268 printf ("Time: %d %s\n", time, ctime (&time));
270 tmptr = localtime (&time);
271 printf ("localtime returns: ");
274 printf ("mktime: %d\n\n", mktime (tmptr));
278 tmptr->tm_hour -= 20;
279 tmptr->tm_mday -= 20;
281 tmptr->tm_year -= 20;
282 tmptr->tm_gmtoff -= 20000; /* this has no effect! */
283 tmptr->tm_zone = NULL; /* nor does this! */
284 tmptr->tm_isdst = -1;
286 printf ("changed ranges: ");
290 result_time = mktime (tmptr);
291 printf ("\n mine: %d\n", result_time);