1*0b459c2cSDavid du Colombier /* Convert struct partime into time_t. */
2*0b459c2cSDavid du Colombier
3*0b459c2cSDavid du Colombier /* Copyright 1992, 1993, 1994, 1995, 1997 Paul Eggert
4*0b459c2cSDavid du Colombier Distributed under license by the Free Software Foundation, Inc.
5*0b459c2cSDavid du Colombier
6*0b459c2cSDavid du Colombier This file is part of RCS.
7*0b459c2cSDavid du Colombier
8*0b459c2cSDavid du Colombier RCS is free software; you can redistribute it and/or modify
9*0b459c2cSDavid du Colombier it under the terms of the GNU General Public License as published by
10*0b459c2cSDavid du Colombier the Free Software Foundation; either version 2, or (at your option)
11*0b459c2cSDavid du Colombier any later version.
12*0b459c2cSDavid du Colombier
13*0b459c2cSDavid du Colombier RCS is distributed in the hope that it will be useful,
14*0b459c2cSDavid du Colombier but WITHOUT ANY WARRANTY; without even the implied warranty of
15*0b459c2cSDavid du Colombier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*0b459c2cSDavid du Colombier GNU General Public License for more details.
17*0b459c2cSDavid du Colombier
18*0b459c2cSDavid du Colombier You should have received a copy of the GNU General Public License
19*0b459c2cSDavid du Colombier along with RCS; see the file COPYING.
20*0b459c2cSDavid du Colombier If not, write to the Free Software Foundation,
21*0b459c2cSDavid du Colombier 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*0b459c2cSDavid du Colombier
23*0b459c2cSDavid du Colombier Report problems and direct all questions to:
24*0b459c2cSDavid du Colombier
25*0b459c2cSDavid du Colombier rcs-bugs@cs.purdue.edu
26*0b459c2cSDavid du Colombier
27*0b459c2cSDavid du Colombier */
28*0b459c2cSDavid du Colombier
29*0b459c2cSDavid du Colombier #if has_conf_h
30*0b459c2cSDavid du Colombier # include <conf.h>
31*0b459c2cSDavid du Colombier #else
32*0b459c2cSDavid du Colombier # if HAVE_CONFIG_H
33*0b459c2cSDavid du Colombier # include <config.h>
34*0b459c2cSDavid du Colombier # else
35*0b459c2cSDavid du Colombier # ifndef __STDC__
36*0b459c2cSDavid du Colombier # define const
37*0b459c2cSDavid du Colombier # endif
38*0b459c2cSDavid du Colombier # endif
39*0b459c2cSDavid du Colombier /* MIPS RISCOS4.52 defines time_t in <sys/types.h> not <time.h>. */
40*0b459c2cSDavid du Colombier # include <sys/types.h>
41*0b459c2cSDavid du Colombier # if HAVE_LIMITS_H
42*0b459c2cSDavid du Colombier # include <limits.h>
43*0b459c2cSDavid du Colombier # endif
44*0b459c2cSDavid du Colombier # ifndef LONG_MIN
45*0b459c2cSDavid du Colombier # define LONG_MIN (-1-2147483647L)
46*0b459c2cSDavid du Colombier # endif
47*0b459c2cSDavid du Colombier # if STDC_HEADERS
48*0b459c2cSDavid du Colombier # include <stdlib.h>
49*0b459c2cSDavid du Colombier # endif
50*0b459c2cSDavid du Colombier # include <time.h>
51*0b459c2cSDavid du Colombier # ifdef __STDC__
52*0b459c2cSDavid du Colombier # define P(x) x
53*0b459c2cSDavid du Colombier # else
54*0b459c2cSDavid du Colombier # define P(x) ()
55*0b459c2cSDavid du Colombier # endif
56*0b459c2cSDavid du Colombier #endif
57*0b459c2cSDavid du Colombier
58*0b459c2cSDavid du Colombier #include <partime.h>
59*0b459c2cSDavid du Colombier #include <maketime.h>
60*0b459c2cSDavid du Colombier
61*0b459c2cSDavid du Colombier char const maketId[] =
62*0b459c2cSDavid du Colombier "$Id: maketime.c,v 5.15 1997/06/17 16:54:36 eggert Exp $";
63*0b459c2cSDavid du Colombier
64*0b459c2cSDavid du Colombier static int isleap P ((int));
65*0b459c2cSDavid du Colombier static int month_days P ((struct tm const *));
66*0b459c2cSDavid du Colombier static time_t maketime P ((struct partime const *, time_t));
67*0b459c2cSDavid du Colombier
68*0b459c2cSDavid du Colombier /* For maximum portability, use only localtime and gmtime.
69*0b459c2cSDavid du Colombier Make no assumptions about the time_t epoch or the range of time_t values.
70*0b459c2cSDavid du Colombier Avoid mktime because it's not universal and because there's no easy,
71*0b459c2cSDavid du Colombier portable way for mktime to yield the inverse of gmtime. */
72*0b459c2cSDavid du Colombier
73*0b459c2cSDavid du Colombier #define TM_YEAR_ORIGIN 1900
74*0b459c2cSDavid du Colombier
75*0b459c2cSDavid du Colombier static int
isleap(y)76*0b459c2cSDavid du Colombier isleap (y)
77*0b459c2cSDavid du Colombier int y;
78*0b459c2cSDavid du Colombier {
79*0b459c2cSDavid du Colombier return (y & 3) == 0 && (y % 100 != 0 || y % 400 == 0);
80*0b459c2cSDavid du Colombier }
81*0b459c2cSDavid du Colombier
82*0b459c2cSDavid du Colombier /* days in year before start of months 0-12 */
83*0b459c2cSDavid du Colombier static int const month_yday[] =
84*0b459c2cSDavid du Colombier {
85*0b459c2cSDavid du Colombier 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
86*0b459c2cSDavid du Colombier };
87*0b459c2cSDavid du Colombier
88*0b459c2cSDavid du Colombier /* Yield the number of days in TM's month. */
89*0b459c2cSDavid du Colombier static int
month_days(tm)90*0b459c2cSDavid du Colombier month_days (tm)
91*0b459c2cSDavid du Colombier struct tm const *tm;
92*0b459c2cSDavid du Colombier {
93*0b459c2cSDavid du Colombier int m = tm->tm_mon;
94*0b459c2cSDavid du Colombier return (month_yday[m + 1] - month_yday[m]
95*0b459c2cSDavid du Colombier + (m == 1 && isleap (tm->tm_year + TM_YEAR_ORIGIN)));
96*0b459c2cSDavid du Colombier }
97*0b459c2cSDavid du Colombier
98*0b459c2cSDavid du Colombier /* Convert UNIXTIME to struct tm form.
99*0b459c2cSDavid du Colombier Use gmtime if available and if !LOCALZONE, localtime otherwise. */
100*0b459c2cSDavid du Colombier struct tm *
time2tm(unixtime,localzone)101*0b459c2cSDavid du Colombier time2tm (unixtime, localzone)
102*0b459c2cSDavid du Colombier time_t unixtime;
103*0b459c2cSDavid du Colombier int localzone;
104*0b459c2cSDavid du Colombier {
105*0b459c2cSDavid du Colombier struct tm *tm;
106*0b459c2cSDavid du Colombier #ifdef TZ_is_unset
107*0b459c2cSDavid du Colombier static char const *TZ;
108*0b459c2cSDavid du Colombier if (!TZ && !(TZ = getenv ("TZ")))
109*0b459c2cSDavid du Colombier TZ_is_unset ("The TZ environment variable is not set; please set it to your timezone");
110*0b459c2cSDavid du Colombier #endif
111*0b459c2cSDavid du Colombier if (localzone || !(tm = gmtime (&unixtime)))
112*0b459c2cSDavid du Colombier tm = localtime (&unixtime);
113*0b459c2cSDavid du Colombier return tm;
114*0b459c2cSDavid du Colombier }
115*0b459c2cSDavid du Colombier
116*0b459c2cSDavid du Colombier /* Yield A - B, measured in seconds. */
117*0b459c2cSDavid du Colombier time_t
difftm(a,b)118*0b459c2cSDavid du Colombier difftm (a, b)
119*0b459c2cSDavid du Colombier struct tm const *a;
120*0b459c2cSDavid du Colombier struct tm const *b;
121*0b459c2cSDavid du Colombier {
122*0b459c2cSDavid du Colombier int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
123*0b459c2cSDavid du Colombier int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
124*0b459c2cSDavid du Colombier int ac = ay / 100 - (ay % 100 < 0);
125*0b459c2cSDavid du Colombier int bc = by / 100 - (by % 100 < 0);
126*0b459c2cSDavid du Colombier int difference_in_day_of_year = a->tm_yday - b->tm_yday;
127*0b459c2cSDavid du Colombier int intervening_leap_days = (((ay >> 2) - (by >> 2))
128*0b459c2cSDavid du Colombier - (ac - bc)
129*0b459c2cSDavid du Colombier + ((ac >> 2) - (bc >> 2)));
130*0b459c2cSDavid du Colombier time_t difference_in_years = ay - by;
131*0b459c2cSDavid du Colombier time_t difference_in_days
132*0b459c2cSDavid du Colombier = (difference_in_years * 365
133*0b459c2cSDavid du Colombier + (intervening_leap_days + difference_in_day_of_year));
134*0b459c2cSDavid du Colombier return (((((difference_in_days * 24
135*0b459c2cSDavid du Colombier + (a->tm_hour - b->tm_hour))
136*0b459c2cSDavid du Colombier * 60)
137*0b459c2cSDavid du Colombier + (a->tm_min - b->tm_min))
138*0b459c2cSDavid du Colombier * 60)
139*0b459c2cSDavid du Colombier + (a->tm_sec - b->tm_sec));
140*0b459c2cSDavid du Colombier }
141*0b459c2cSDavid du Colombier
142*0b459c2cSDavid du Colombier /*
143*0b459c2cSDavid du Colombier * Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth.
144*0b459c2cSDavid du Colombier * Adjust only T's year, mon, mday, hour, min and sec members;
145*0b459c2cSDavid du Colombier * plus adjust wday if it is defined.
146*0b459c2cSDavid du Colombier */
147*0b459c2cSDavid du Colombier void
adjzone(t,seconds)148*0b459c2cSDavid du Colombier adjzone (t, seconds)
149*0b459c2cSDavid du Colombier register struct tm *t;
150*0b459c2cSDavid du Colombier long seconds;
151*0b459c2cSDavid du Colombier {
152*0b459c2cSDavid du Colombier /*
153*0b459c2cSDavid du Colombier * This code can be off by a second if SECONDS is not a multiple of 60,
154*0b459c2cSDavid du Colombier * if T is local time, and if a leap second happens during this minute.
155*0b459c2cSDavid du Colombier * But this bug has never occurred, and most likely will not ever occur.
156*0b459c2cSDavid du Colombier * Liberia, the last country for which SECONDS % 60 was nonzero,
157*0b459c2cSDavid du Colombier * switched to UTC in May 1972; the first leap second was in June 1972.
158*0b459c2cSDavid du Colombier */
159*0b459c2cSDavid du Colombier int leap_second = t->tm_sec == 60;
160*0b459c2cSDavid du Colombier long sec = seconds + (t->tm_sec - leap_second);
161*0b459c2cSDavid du Colombier if (sec < 0)
162*0b459c2cSDavid du Colombier {
163*0b459c2cSDavid du Colombier if ((t->tm_min -= (59 - sec) / 60) < 0)
164*0b459c2cSDavid du Colombier {
165*0b459c2cSDavid du Colombier if ((t->tm_hour -= (59 - t->tm_min) / 60) < 0)
166*0b459c2cSDavid du Colombier {
167*0b459c2cSDavid du Colombier t->tm_hour += 24;
168*0b459c2cSDavid du Colombier if (TM_DEFINED (t->tm_wday) && --t->tm_wday < 0)
169*0b459c2cSDavid du Colombier t->tm_wday = 6;
170*0b459c2cSDavid du Colombier if (--t->tm_mday <= 0)
171*0b459c2cSDavid du Colombier {
172*0b459c2cSDavid du Colombier if (--t->tm_mon < 0)
173*0b459c2cSDavid du Colombier {
174*0b459c2cSDavid du Colombier --t->tm_year;
175*0b459c2cSDavid du Colombier t->tm_mon = 11;
176*0b459c2cSDavid du Colombier }
177*0b459c2cSDavid du Colombier t->tm_mday = month_days (t);
178*0b459c2cSDavid du Colombier }
179*0b459c2cSDavid du Colombier }
180*0b459c2cSDavid du Colombier t->tm_min += 24 * 60;
181*0b459c2cSDavid du Colombier }
182*0b459c2cSDavid du Colombier sec += 24L * 60 * 60;
183*0b459c2cSDavid du Colombier }
184*0b459c2cSDavid du Colombier else if (60 <= (t->tm_min += sec / 60))
185*0b459c2cSDavid du Colombier if (24 <= (t->tm_hour += t->tm_min / 60))
186*0b459c2cSDavid du Colombier {
187*0b459c2cSDavid du Colombier t->tm_hour -= 24;
188*0b459c2cSDavid du Colombier if (TM_DEFINED (t->tm_wday) && ++t->tm_wday == 7)
189*0b459c2cSDavid du Colombier t->tm_wday = 0;
190*0b459c2cSDavid du Colombier if (month_days (t) < ++t->tm_mday)
191*0b459c2cSDavid du Colombier {
192*0b459c2cSDavid du Colombier if (11 < ++t->tm_mon)
193*0b459c2cSDavid du Colombier {
194*0b459c2cSDavid du Colombier ++t->tm_year;
195*0b459c2cSDavid du Colombier t->tm_mon = 0;
196*0b459c2cSDavid du Colombier }
197*0b459c2cSDavid du Colombier t->tm_mday = 1;
198*0b459c2cSDavid du Colombier }
199*0b459c2cSDavid du Colombier }
200*0b459c2cSDavid du Colombier t->tm_min %= 60;
201*0b459c2cSDavid du Colombier t->tm_sec = (int) (sec % 60) + leap_second;
202*0b459c2cSDavid du Colombier }
203*0b459c2cSDavid du Colombier
204*0b459c2cSDavid du Colombier /*
205*0b459c2cSDavid du Colombier * Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise.
206*0b459c2cSDavid du Colombier * Use only TM's year, mon, mday, hour, min, and sec members.
207*0b459c2cSDavid du Colombier * Ignore TM's old tm_yday and tm_wday, but fill in their correct values.
208*0b459c2cSDavid du Colombier * Yield -1 on failure (e.g. a member out of range).
209*0b459c2cSDavid du Colombier * Posix 1003.1-1990 doesn't allow leap seconds, but some implementations
210*0b459c2cSDavid du Colombier * have them anyway, so allow them if localtime/gmtime does.
211*0b459c2cSDavid du Colombier */
212*0b459c2cSDavid du Colombier time_t
tm2time(tm,localzone)213*0b459c2cSDavid du Colombier tm2time (tm, localzone)
214*0b459c2cSDavid du Colombier struct tm *tm;
215*0b459c2cSDavid du Colombier int localzone;
216*0b459c2cSDavid du Colombier {
217*0b459c2cSDavid du Colombier /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */
218*0b459c2cSDavid du Colombier static time_t t_cache[2];
219*0b459c2cSDavid du Colombier static struct tm tm_cache[2];
220*0b459c2cSDavid du Colombier
221*0b459c2cSDavid du Colombier time_t d, gt;
222*0b459c2cSDavid du Colombier struct tm const *gtm;
223*0b459c2cSDavid du Colombier /*
224*0b459c2cSDavid du Colombier * The maximum number of iterations should be enough to handle any
225*0b459c2cSDavid du Colombier * combinations of leap seconds, time zone rule changes, and solar time.
226*0b459c2cSDavid du Colombier * 4 is probably enough; we use a bigger number just to be safe.
227*0b459c2cSDavid du Colombier */
228*0b459c2cSDavid du Colombier int remaining_tries = 8;
229*0b459c2cSDavid du Colombier
230*0b459c2cSDavid du Colombier /* Avoid subscript errors. */
231*0b459c2cSDavid du Colombier if (12 <= (unsigned) tm->tm_mon)
232*0b459c2cSDavid du Colombier return -1;
233*0b459c2cSDavid du Colombier
234*0b459c2cSDavid du Colombier tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday
235*0b459c2cSDavid du Colombier - (tm->tm_mon < 2 || !isleap (tm->tm_year + TM_YEAR_ORIGIN));
236*0b459c2cSDavid du Colombier
237*0b459c2cSDavid du Colombier /* Make a first guess. */
238*0b459c2cSDavid du Colombier gt = t_cache[localzone];
239*0b459c2cSDavid du Colombier gtm = gt ? &tm_cache[localzone] : time2tm (gt, localzone);
240*0b459c2cSDavid du Colombier
241*0b459c2cSDavid du Colombier /* Repeatedly use the error from the guess to improve the guess. */
242*0b459c2cSDavid du Colombier while ((d = difftm (tm, gtm)) != 0)
243*0b459c2cSDavid du Colombier {
244*0b459c2cSDavid du Colombier if (--remaining_tries == 0)
245*0b459c2cSDavid du Colombier return -1;
246*0b459c2cSDavid du Colombier gt += d;
247*0b459c2cSDavid du Colombier gtm = time2tm (gt, localzone);
248*0b459c2cSDavid du Colombier }
249*0b459c2cSDavid du Colombier
250*0b459c2cSDavid du Colombier /*
251*0b459c2cSDavid du Colombier * Check that the guess actually matches;
252*0b459c2cSDavid du Colombier * overflow can cause difftm to yield 0 even on differing times,
253*0b459c2cSDavid du Colombier * or tm may have members out of range (e.g. bad leap seconds).
254*0b459c2cSDavid du Colombier */
255*0b459c2cSDavid du Colombier #define TM_DIFFER(a,b) \
256*0b459c2cSDavid du Colombier ( \
257*0b459c2cSDavid du Colombier ((a)->tm_year ^ (b)->tm_year) | \
258*0b459c2cSDavid du Colombier ((a)->tm_mon ^ (b)->tm_mon) | \
259*0b459c2cSDavid du Colombier ((a)->tm_mday ^ (b)->tm_mday) | \
260*0b459c2cSDavid du Colombier ((a)->tm_hour ^ (b)->tm_hour) | \
261*0b459c2cSDavid du Colombier ((a)->tm_min ^ (b)->tm_min) | \
262*0b459c2cSDavid du Colombier ((a)->tm_sec ^ (b)->tm_sec) \
263*0b459c2cSDavid du Colombier )
264*0b459c2cSDavid du Colombier if (TM_DIFFER (tm, gtm))
265*0b459c2cSDavid du Colombier {
266*0b459c2cSDavid du Colombier /*
267*0b459c2cSDavid du Colombier * If gt is a leap second, try gt+1; if it is one greater than
268*0b459c2cSDavid du Colombier * a leap second, try gt-1; otherwise, it doesn't matter.
269*0b459c2cSDavid du Colombier * Leap seconds always fall at month end.
270*0b459c2cSDavid du Colombier */
271*0b459c2cSDavid du Colombier int yd = tm->tm_year - gtm->tm_year;
272*0b459c2cSDavid du Colombier gt += yd + (yd ? 0 : tm->tm_mon - gtm->tm_mon);
273*0b459c2cSDavid du Colombier gtm = time2tm (gt, localzone);
274*0b459c2cSDavid du Colombier if (TM_DIFFER (tm, gtm))
275*0b459c2cSDavid du Colombier return -1;
276*0b459c2cSDavid du Colombier }
277*0b459c2cSDavid du Colombier t_cache[localzone] = gt;
278*0b459c2cSDavid du Colombier tm_cache[localzone] = *gtm;
279*0b459c2cSDavid du Colombier
280*0b459c2cSDavid du Colombier tm->tm_wday = gtm->tm_wday;
281*0b459c2cSDavid du Colombier return gt;
282*0b459c2cSDavid du Colombier }
283*0b459c2cSDavid du Colombier
284*0b459c2cSDavid du Colombier /*
285*0b459c2cSDavid du Colombier * Check *PT and convert it to time_t.
286*0b459c2cSDavid du Colombier * If it is incompletely specified, use DEFAULT_TIME to fill it out.
287*0b459c2cSDavid du Colombier * Use localtime if PT->zone is the special value TM_LOCAL_ZONE.
288*0b459c2cSDavid du Colombier * Yield -1 on failure.
289*0b459c2cSDavid du Colombier * ISO 8601 day-of-year and week numbers are not yet supported.
290*0b459c2cSDavid du Colombier */
291*0b459c2cSDavid du Colombier static time_t
maketime(pt,default_time)292*0b459c2cSDavid du Colombier maketime (pt, default_time)
293*0b459c2cSDavid du Colombier struct partime const *pt;
294*0b459c2cSDavid du Colombier time_t default_time;
295*0b459c2cSDavid du Colombier {
296*0b459c2cSDavid du Colombier int localzone, wday;
297*0b459c2cSDavid du Colombier struct tm tm;
298*0b459c2cSDavid du Colombier struct tm *tm0 = 0;
299*0b459c2cSDavid du Colombier time_t r;
300*0b459c2cSDavid du Colombier
301*0b459c2cSDavid du Colombier tm0 = 0; /* Keep gcc -Wall happy. */
302*0b459c2cSDavid du Colombier localzone = pt->zone == TM_LOCAL_ZONE;
303*0b459c2cSDavid du Colombier
304*0b459c2cSDavid du Colombier tm = pt->tm;
305*0b459c2cSDavid du Colombier
306*0b459c2cSDavid du Colombier if (TM_DEFINED (pt->ymodulus) || !TM_DEFINED (tm.tm_year))
307*0b459c2cSDavid du Colombier {
308*0b459c2cSDavid du Colombier /* Get tm corresponding to default time. */
309*0b459c2cSDavid du Colombier tm0 = time2tm (default_time, localzone);
310*0b459c2cSDavid du Colombier if (!localzone)
311*0b459c2cSDavid du Colombier adjzone (tm0, pt->zone);
312*0b459c2cSDavid du Colombier }
313*0b459c2cSDavid du Colombier
314*0b459c2cSDavid du Colombier if (TM_DEFINED (pt->ymodulus))
315*0b459c2cSDavid du Colombier tm.tm_year +=
316*0b459c2cSDavid du Colombier (tm0->tm_year + TM_YEAR_ORIGIN) / pt->ymodulus * pt->ymodulus;
317*0b459c2cSDavid du Colombier else if (!TM_DEFINED (tm.tm_year))
318*0b459c2cSDavid du Colombier {
319*0b459c2cSDavid du Colombier /* Set default year, month, day from current time. */
320*0b459c2cSDavid du Colombier tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN;
321*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_mon))
322*0b459c2cSDavid du Colombier {
323*0b459c2cSDavid du Colombier tm.tm_mon = tm0->tm_mon;
324*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_mday))
325*0b459c2cSDavid du Colombier tm.tm_mday = tm0->tm_mday;
326*0b459c2cSDavid du Colombier }
327*0b459c2cSDavid du Colombier }
328*0b459c2cSDavid du Colombier
329*0b459c2cSDavid du Colombier /* Convert from partime year (Gregorian) to Posix year. */
330*0b459c2cSDavid du Colombier tm.tm_year -= TM_YEAR_ORIGIN;
331*0b459c2cSDavid du Colombier
332*0b459c2cSDavid du Colombier /* Set remaining default fields to be their minimum values. */
333*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_mon))
334*0b459c2cSDavid du Colombier tm.tm_mon = 0;
335*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_mday))
336*0b459c2cSDavid du Colombier tm.tm_mday = 1;
337*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_hour))
338*0b459c2cSDavid du Colombier tm.tm_hour = 0;
339*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_min))
340*0b459c2cSDavid du Colombier tm.tm_min = 0;
341*0b459c2cSDavid du Colombier if (!TM_DEFINED (tm.tm_sec))
342*0b459c2cSDavid du Colombier tm.tm_sec = 0;
343*0b459c2cSDavid du Colombier
344*0b459c2cSDavid du Colombier if (!localzone)
345*0b459c2cSDavid du Colombier adjzone (&tm, -pt->zone);
346*0b459c2cSDavid du Colombier wday = tm.tm_wday;
347*0b459c2cSDavid du Colombier
348*0b459c2cSDavid du Colombier /* Convert and fill in the rest of the tm. */
349*0b459c2cSDavid du Colombier r = tm2time (&tm, localzone);
350*0b459c2cSDavid du Colombier
351*0b459c2cSDavid du Colombier /* Check weekday. */
352*0b459c2cSDavid du Colombier if (r != -1 && TM_DEFINED (wday) && wday != tm.tm_wday)
353*0b459c2cSDavid du Colombier return -1;
354*0b459c2cSDavid du Colombier
355*0b459c2cSDavid du Colombier return r;
356*0b459c2cSDavid du Colombier }
357*0b459c2cSDavid du Colombier
358*0b459c2cSDavid du Colombier /* Parse a free-format date in SOURCE, yielding a Unix format time. */
359*0b459c2cSDavid du Colombier time_t
str2time(source,default_time,default_zone)360*0b459c2cSDavid du Colombier str2time (source, default_time, default_zone)
361*0b459c2cSDavid du Colombier char const *source;
362*0b459c2cSDavid du Colombier time_t default_time;
363*0b459c2cSDavid du Colombier long default_zone;
364*0b459c2cSDavid du Colombier {
365*0b459c2cSDavid du Colombier struct partime pt;
366*0b459c2cSDavid du Colombier
367*0b459c2cSDavid du Colombier if (*partime (source, &pt))
368*0b459c2cSDavid du Colombier return -1;
369*0b459c2cSDavid du Colombier if (pt.zone == TM_UNDEFINED_ZONE)
370*0b459c2cSDavid du Colombier pt.zone = default_zone;
371*0b459c2cSDavid du Colombier return maketime (&pt, default_time);
372*0b459c2cSDavid du Colombier }
373*0b459c2cSDavid du Colombier
374*0b459c2cSDavid du Colombier #if TEST
375*0b459c2cSDavid du Colombier #include <stdio.h>
376*0b459c2cSDavid du Colombier int
main(argc,argv)377*0b459c2cSDavid du Colombier main (argc, argv)
378*0b459c2cSDavid du Colombier int argc;
379*0b459c2cSDavid du Colombier char **argv;
380*0b459c2cSDavid du Colombier {
381*0b459c2cSDavid du Colombier time_t default_time = time ((time_t *) 0);
382*0b459c2cSDavid du Colombier long default_zone = argv[1] ? atol (argv[1]) : 0;
383*0b459c2cSDavid du Colombier char buf[1000];
384*0b459c2cSDavid du Colombier while (fgets (buf, sizeof (buf), stdin))
385*0b459c2cSDavid du Colombier {
386*0b459c2cSDavid du Colombier time_t t = str2time (buf, default_time, default_zone);
387*0b459c2cSDavid du Colombier printf ("%s", asctime (gmtime (&t)));
388*0b459c2cSDavid du Colombier }
389*0b459c2cSDavid du Colombier return 0;
390*0b459c2cSDavid du Colombier }
391*0b459c2cSDavid du Colombier #endif
392