1 /* 2 * mktime.c 3 * Original Author: G. Haley 4 * 5 * Converts the broken-down time, expressed as local time, in the structure 6 * pointed to by tim_p into a calendar time value. The original values of the 7 * tm_wday and tm_yday fields of the structure are ignored, and the original 8 * values of the other fields have no restrictions. On successful completion 9 * the fields of the structure are set to represent the specified calendar 10 * time. Returns the specified calendar time. If the calendar time can not be 11 * represented, returns the value (time_t) -1. 12 * 13 * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland. 14 */ 15 16 /* 17 FUNCTION 18 <<mktime>>---convert time to arithmetic representation 19 20 INDEX 21 mktime 22 23 ANSI_SYNOPSIS 24 #include <time.h> 25 time_t mktime(struct tm *<[timp]>); 26 27 TRAD_SYNOPSIS 28 #include <time.h> 29 time_t mktime(<[timp]>) 30 struct tm *<[timp]>; 31 32 DESCRIPTION 33 <<mktime>> assumes the time at <[timp]> is a local time, and converts 34 its representation from the traditional representation defined by 35 <<struct tm>> into a representation suitable for arithmetic. 36 37 <<localtime>> is the inverse of <<mktime>>. 38 39 RETURNS 40 If the contents of the structure at <[timp]> do not form a valid 41 calendar time representation, the result is <<-1>>. Otherwise, the 42 result is the time, converted to a <<time_t>> value. 43 44 PORTABILITY 45 ANSI C requires <<mktime>>. 46 47 <<mktime>> requires no supporting OS subroutines. 48 */ 49 50 #include <stdlib.h> 51 #include <time.h> 52 #include "local.h" 53 54 #define _SEC_IN_MINUTE 60L 55 #define _SEC_IN_HOUR 3600L 56 #define _SEC_IN_DAY 86400L 57 58 static _CONST int DAYS_IN_MONTH[12] = 59 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 60 61 #define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x]) 62 63 static _CONST int _DAYS_BEFORE_MONTH[12] = 64 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; 65 66 #define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0)) 67 #define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365) 68 69 static void 70 _DEFUN(validate_structure, (tim_p), 71 struct tm *tim_p) 72 { 73 div_t res; 74 int days_in_feb = 28; 75 76 /* calculate time & date to account for out of range values */ 77 if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59) 78 { 79 res = div (tim_p->tm_sec, 60); 80 tim_p->tm_min += res.quot; 81 if ((tim_p->tm_sec = res.rem) < 0) 82 { 83 tim_p->tm_sec += 60; 84 --tim_p->tm_min; 85 } 86 } 87 88 if (tim_p->tm_min < 0 || tim_p->tm_min > 59) 89 { 90 res = div (tim_p->tm_min, 60); 91 tim_p->tm_hour += res.quot; 92 if ((tim_p->tm_min = res.rem) < 0) 93 { 94 tim_p->tm_min += 60; 95 --tim_p->tm_hour; 96 } 97 } 98 99 if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23) 100 { 101 res = div (tim_p->tm_hour, 24); 102 tim_p->tm_mday += res.quot; 103 if ((tim_p->tm_hour = res.rem) < 0) 104 { 105 tim_p->tm_hour += 24; 106 --tim_p->tm_mday; 107 } 108 } 109 110 if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11) 111 { 112 res = div (tim_p->tm_mon, 12); 113 tim_p->tm_year += res.quot; 114 if ((tim_p->tm_mon = res.rem) < 0) 115 { 116 tim_p->tm_mon += 12; 117 --tim_p->tm_year; 118 } 119 } 120 121 if (_DAYS_IN_YEAR (tim_p->tm_year) == 366) 122 days_in_feb = 29; 123 124 if (tim_p->tm_mday <= 0) 125 { 126 while (tim_p->tm_mday <= 0) 127 { 128 if (--tim_p->tm_mon == -1) 129 { 130 tim_p->tm_year--; 131 tim_p->tm_mon = 11; 132 days_in_feb = 133 ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? 134 29 : 28); 135 } 136 tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon); 137 } 138 } 139 else 140 { 141 while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon)) 142 { 143 tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon); 144 if (++tim_p->tm_mon == 12) 145 { 146 tim_p->tm_year++; 147 tim_p->tm_mon = 0; 148 days_in_feb = 149 ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? 150 29 : 28); 151 } 152 } 153 } 154 } 155 156 time_t 157 _DEFUN(mktime, (tim_p), 158 struct tm *tim_p) 159 { 160 time_t tim = 0; 161 long days = 0; 162 int year, isdst=0; 163 __tzinfo_type *tz = __gettzinfo (); 164 165 /* validate structure */ 166 validate_structure (tim_p); 167 168 /* compute hours, minutes, seconds */ 169 tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) + 170 (tim_p->tm_hour * _SEC_IN_HOUR); 171 172 /* compute days in year */ 173 days += tim_p->tm_mday - 1; 174 days += _DAYS_BEFORE_MONTH[tim_p->tm_mon]; 175 if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366) 176 days++; 177 178 /* compute day of the year */ 179 tim_p->tm_yday = days; 180 181 if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000) 182 return (time_t) -1; 183 184 /* compute days in other years */ 185 if ((year = tim_p->tm_year) > 70) 186 { 187 for (year = 70; year < tim_p->tm_year; year++) 188 days += _DAYS_IN_YEAR (year); 189 } 190 else if (year < 70) 191 { 192 for (year = 69; year > tim_p->tm_year; year--) 193 days -= _DAYS_IN_YEAR (year); 194 days -= _DAYS_IN_YEAR (year); 195 } 196 197 /* compute total seconds */ 198 tim += (days * _SEC_IN_DAY); 199 200 TZ_LOCK; 201 202 _tzset_unlocked (); 203 204 if (_daylight) 205 { 206 int tm_isdst; 207 int y = tim_p->tm_year + YEAR_BASE; 208 /* Convert user positive into 1 */ 209 tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst; 210 isdst = tm_isdst; 211 212 if (y == tz->__tzyear || __tzcalc_limits (y)) 213 { 214 /* calculate start of dst in dst local time and 215 start of std in both std local time and dst local time */ 216 time_t startdst_dst = tz->__tzrule[0].change 217 - (time_t) tz->__tzrule[1].offset; 218 time_t startstd_dst = tz->__tzrule[1].change 219 - (time_t) tz->__tzrule[1].offset; 220 time_t startstd_std = tz->__tzrule[1].change 221 - (time_t) tz->__tzrule[0].offset; 222 /* if the time is in the overlap between dst and std local times */ 223 if (tim >= startstd_std && tim < startstd_dst) 224 ; /* we let user decide or leave as -1 */ 225 else 226 { 227 isdst = (tz->__tznorth 228 ? (tim >= startdst_dst && tim < startstd_std) 229 : (tim >= startdst_dst || tim < startstd_std)); 230 /* if user committed and was wrong, perform correction, but not 231 * if the user has given a negative value (which 232 * asks mktime() to determine if DST is in effect or not) */ 233 if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1) 234 { 235 /* we either subtract or add the difference between 236 time zone offsets, depending on which way the user got it 237 wrong. The diff is typically one hour, or 3600 seconds, 238 and should fit in a 16-bit int, even though offset 239 is a long to accomodate 12 hours. */ 240 int diff = (int) (tz->__tzrule[0].offset 241 - tz->__tzrule[1].offset); 242 if (!isdst) 243 diff = -diff; 244 tim_p->tm_sec += diff; 245 tim += diff; /* we also need to correct our current time calculation */ 246 int mday = tim_p->tm_mday; 247 validate_structure (tim_p); 248 mday = tim_p->tm_mday - mday; 249 /* roll over occurred */ 250 if (mday) { 251 /* compensate for month roll overs */ 252 if (mday > 1) 253 mday = -1; 254 else if (mday < -1) 255 mday = 1; 256 /* update days for wday calculation */ 257 days += mday; 258 /* handle yday */ 259 if ((tim_p->tm_yday += mday) < 0) { 260 --year; 261 tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1; 262 } else { 263 mday = _DAYS_IN_YEAR(year); 264 if (tim_p->tm_yday > (mday - 1)) 265 tim_p->tm_yday -= mday; 266 } 267 } 268 } 269 } 270 } 271 } 272 273 /* add appropriate offset to put time in gmt format */ 274 if (isdst == 1) 275 tim += (time_t) tz->__tzrule[1].offset; 276 else /* otherwise assume std time */ 277 tim += (time_t) tz->__tzrule[0].offset; 278 279 TZ_UNLOCK; 280 281 /* reset isdst flag to what we have calculated */ 282 tim_p->tm_isdst = isdst; 283 284 /* compute day of the week */ 285 if ((tim_p->tm_wday = (days + 4) % 7) < 0) 286 tim_p->tm_wday += 7; 287 288 return tim; 289 } 290