1
/* free mktime function
2
Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>
3
and Michael Haertel <mike@ai.mit.edu>
4
Unlimited distribution permitted provided this copyright notice is
5
retained and any functional modifications are prominently identified. */
7
/* Revised 1997 by Christian Spieler:
8
The code was changed to get more conformance with ANSI's (resp. modern
9
UNIX releases) definition for mktime():
10
- Added adjustment for out-of-range values in the fields of struct tm.
11
- Added iterations to get the correct UTC result for input values at
12
the gaps when daylight saving time is switched on or off.
13
- Allow forcing of DST "on" or DST "off" by setting `tm_isdst' field in
14
the tm struct to positive number resp. zero. The `tm_isdst' field must
15
be negative on entrance of mktime() to enable automatic determination
16
if DST is in effect for the requested local time.
17
- Added optional check for overflowing the time_t range. */
19
/* Note: This version of mktime is ignorant of the tzfile.
20
When the tm structure passed to mktime represents a local time that
21
is valid both as DST time and as standard time (= time value in the
22
gap when switching from DST back to standard time), the behaviour
23
for `tm_isdst < 0' depends on the current timezone: TZ east of GMT
24
assumes winter time, TZ west of GMT assumes summer time.
25
Although mktime() (resp. mkgmtime()) tries to adjust for invalid values
26
of struct tm members, this may fail for input values that are far away
27
from the valid ranges. The adjustment process does not check for overflows
28
or wrap arounds in the struct tm components. */
44
time_t mkgmtime OF((struct tm *));
45
time_t mktime OF((struct tm *));
47
/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
48
of the local time and date in the exploded time structure `tm',
49
adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
50
If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
51
tm_isdst is determined and returned. Otherwise, mktime() assumes this
52
field as valid; its information is used when converting local time
54
Return -1 if time in `tm' cannot be represented as time_t value. */
60
struct tm *ltm; /* Local time. */
61
time_t loctime; /* The time_t value of local time. */
62
time_t then; /* The time to return. */
63
long tzoffset_adj; /* timezone-adjustment `remainder' */
64
int bailout_cnt; /* counter of tries for tz correction */
65
int save_isdst; /* Copy of the tm->isdst input value */
67
save_isdst = tm->tm_isdst;
68
loctime = mkgmtime(tm);
70
tm->tm_isdst = save_isdst;
74
/* Correct for the timezone and any daylight savings time.
75
The correction is verified and repeated when not correct, to
76
take into account the rare case that a change to or from daylight
77
savings time occurs between when it is the time in `tm' locally
78
and when it is that time in Greenwich. After the second correction,
79
the "timezone & daylight" offset should be correct in all cases. To
80
be sure, we allow a third try, but then the loop is stopped. */
84
ltm = localtime(&then);
85
if (ltm == (struct tm *)NULL ||
86
(tzoffset_adj = loctime - mkgmtime(ltm)) == 0L)
89
} while (--bailout_cnt > 0);
91
if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) {
92
/* Signal failure if timezone adjustment did not converge. */
93
tm->tm_isdst = save_isdst;
97
if (save_isdst >= 0) {
98
if (ltm->tm_isdst && !save_isdst)
100
if (then + 3600 < then)
105
else if (!ltm->tm_isdst && save_isdst)
107
if (then - 3600 > then)
112
ltm->tm_isdst = save_isdst;
115
if (tm != ltm) /* `tm' may already point to localtime's internal storage */
122
#ifndef NO_TIME_T_MAX
123
/* Provide default values for the upper limit of the time_t range.
124
These are the result of the decomposition into a `struct tm' for
125
the time value 0xFFFFFFFEL ( = (time_t)-2 ).
126
Note: `(time_t)-1' is reserved for "invalid time"! */
128
# define TM_YEAR_MAX 2106
131
# define TM_MON_MAX 1 /* February */
134
# define TM_MDAY_MAX 7
137
# define TM_HOUR_MAX 6
140
# define TM_MIN_MAX 28
143
# define TM_SEC_MAX 14
145
#endif /* NO_TIME_T_MAX */
147
/* Adjusts out-of-range values for `tm' field `tm_member'. */
148
#define ADJUST_TM(tm_member, tm_carry, modulus) \
149
if ((tm_member) < 0) { \
150
tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
151
tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
152
} else if ((tm_member) >= (modulus)) { \
153
tm_carry += (tm_member) / (modulus); \
154
tm_member = (tm_member) % (modulus); \
157
/* Nonzero if `y' is a leap year, else zero. */
158
#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
160
/* Number of leap years from 1970 to `y' (not including `y' itself). */
161
#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
163
/* Additional leapday in February of leap years. */
164
#define leapday(m, y) ((m) == 1 && leap (y))
166
/* Length of month `m' (0 .. 11) */
167
#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
169
/* Accumulated number of days from 01-Jan up to start of current month. */
170
static ZCONST short ydays[] =
172
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
175
/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
176
of the Greenwich Mean time and date in the exploded time structure `tm'.
177
This function does always put back normalized values into the `tm' struct,
178
parameter, including the calculated numbers for `tm->tm_yday',
179
`tm->tm_wday', and `tm->tm_isdst'.
180
Returns -1 if the time in the `tm' parameter cannot be represented
181
as valid `time_t' number. */
187
int years, months, days, hours, minutes, seconds;
189
years = tm->tm_year + 1900; /* year - 1900 -> year */
190
months = tm->tm_mon; /* 0..11 */
191
days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
192
hours = tm->tm_hour; /* 0..23 */
193
minutes = tm->tm_min; /* 0..59 */
194
seconds = tm->tm_sec; /* 0..61 in ANSI C. */
196
ADJUST_TM(seconds, minutes, 60)
197
ADJUST_TM(minutes, hours, 60)
198
ADJUST_TM(hours, days, 24)
199
ADJUST_TM(months, years, 12)
206
days += monthlen(months, years);
209
while (days >= monthlen(months, years)) {
210
days -= monthlen(months, years);
211
if (++months >= 12) {
217
/* Restore adjusted values in tm structure */
218
tm->tm_year = years - 1900;
220
tm->tm_mday = days + 1;
222
tm->tm_min = minutes;
223
tm->tm_sec = seconds;
225
/* Set `days' to the number of days into the year. */
226
days += ydays[months] + (months > 1 && leap (years));
229
/* Now calculate `days' to the number of days since Jan 1, 1970. */
230
days = (unsigned)days + 365 * (unsigned)(years - 1970) +
231
(unsigned)(nleap (years));
232
tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
238
#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
239
#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
240
if (years > TM_YEAR_MAX ||
241
(years == TM_YEAR_MAX &&
242
(tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
243
(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
244
(tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
245
(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
246
(hours > TM_HOUR_MAX ||
247
(hours == TM_HOUR_MAX &&
248
(minutes > TM_MIN_MAX ||
249
(minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
254
return (time_t)(86400L * (unsigned long)(unsigned)days +
255
3600L * (unsigned long)hours +
256
(unsigned long)(60 * minutes + seconds));
259
const char *BOINC_RCSID_945276575a = "$Id: mktime.c 4979 2005-01-02 18:29:53Z ballen $";