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. */ 6 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. */ 18 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. */ 29 30#ifndef OF 31# ifdef __STDC__ 32# define OF(a) a 33# else 34# define OF(a) () 35# endif 36#endif 37 38#ifndef ZCONST 39# define ZCONST const 40#endif 41 42#include <time.h> 43 44time_t mkgmtime OF((struct tm *)); 45time_t mktime OF((struct tm *)); 46 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 53 to UTC. 54 Return -1 if time in `tm' cannot be represented as time_t value. */ 55 56time_t 57mktime(tm) 58 struct tm *tm; 59{ 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 */ 66 67 save_isdst = tm->tm_isdst; 68 loctime = mkgmtime(tm); 69 if (loctime == -1) { 70 tm->tm_isdst = save_isdst; 71 return (time_t)-1; 72 } 73 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. */ 81 bailout_cnt = 3; 82 then = loctime; 83 do { 84 ltm = localtime(&then); 85 if (ltm == (struct tm *)NULL || 86 (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L) 87 break; 88 then += tzoffset_adj; 89 } while (--bailout_cnt > 0); 90 91 if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) { 92 /* Signal failure if timezone adjustment did not converge. */ 93 tm->tm_isdst = save_isdst; 94 return (time_t)-1; 95 } 96 97 if (save_isdst >= 0) { 98 if (ltm->tm_isdst && !save_isdst) 99 { 100 if (then + 3600 < then) 101 then = (time_t)-1; 102 else 103 then += 3600; 104 } 105 else if (!ltm->tm_isdst && save_isdst) 106 { 107 if (then - 3600 > then) 108 then = (time_t)-1; 109 else 110 then -= 3600; 111 } 112 ltm->tm_isdst = save_isdst; 113 } 114 115 if (tm != ltm) /* `tm' may already point to localtime's internal storage */ 116 *tm = *ltm; 117 118 return then; 119} 120 121 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"! */ 127# ifndef TM_YEAR_MAX 128# define TM_YEAR_MAX 2106 129# endif 130# ifndef TM_MON_MAX 131# define TM_MON_MAX 1 /* February */ 132# endif 133# ifndef TM_MDAY_MAX 134# define TM_MDAY_MAX 7 135# endif 136# ifndef TM_HOUR_MAX 137# define TM_HOUR_MAX 6 138# endif 139# ifndef TM_MIN_MAX 140# define TM_MIN_MAX 28 141# endif 142# ifndef TM_SEC_MAX 143# define TM_SEC_MAX 14 144# endif 145#endif /* NO_TIME_T_MAX */ 146 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); \ 155 } 156 157/* Nonzero if `y' is a leap year, else zero. */ 158#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) 159 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) 162 163/* Additional leapday in February of leap years. */ 164#define leapday(m, y) ((m) == 1 && leap (y)) 165 166/* Length of month `m' (0 .. 11) */ 167#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y)) 168 169/* Accumulated number of days from 01-Jan up to start of current month. */ 170static ZCONST short ydays[] = 171{ 172 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 173}; 174 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. */ 182 183time_t 184mkgmtime(tm) 185 struct tm *tm; 186{ 187 int years, months, days, hours, minutes, seconds; 188 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. */ 195 196 ADJUST_TM(seconds, minutes, 60) 197 ADJUST_TM(minutes, hours, 60) 198 ADJUST_TM(hours, days, 24) 199 ADJUST_TM(months, years, 12) 200 if (days < 0) 201 do { 202 if (--months < 0) { 203 --years; 204 months = 11; 205 } 206 days += monthlen(months, years); 207 } while (days < 0); 208 else 209 while (days >= monthlen(months, years)) { 210 days -= monthlen(months, years); 211 if (++months >= 12) { 212 ++years; 213 months = 0; 214 } 215 } 216 217 /* Restore adjusted values in tm structure */ 218 tm->tm_year = years - 1900; 219 tm->tm_mon = months; 220 tm->tm_mday = days + 1; 221 tm->tm_hour = hours; 222 tm->tm_min = minutes; 223 tm->tm_sec = seconds; 224 225 /* Set `days' to the number of days into the year. */ 226 days += ydays[months] + (months > 1 && leap (years)); 227 tm->tm_yday = days; 228 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. */ 233 tm->tm_isdst = 0; 234 235 if (years < 1970) 236 return (time_t)-1; 237 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) ))))))) 250 return (time_t)-1; 251#endif 252#endif 253 254 return (time_t)(86400L * (unsigned long)(unsigned)days + 255 3600L * (unsigned long)hours + 256 (unsigned long)(60 * minutes + seconds)); 257} 258