--- mktime.c 2011-08-19 10:14:18.000000000 -0400 +++ /Users/steven/Desktop/newlib_mktime.txt 2011-08-27 06:32:15.000000000 -0400 @@ -11,6 +11,7 @@ * represented, returns the value (time_t) -1. * * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland. + * Modifications: New timezone logic - 27 August 2011 Steve Abner. */ /* @@ -66,12 +67,12 @@ #define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0)) #define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365) -static void +static int _DEFUN(validate_structure, (tim_p), struct tm *tim_p) { div_t res; - int days_in_feb = 28; + int days_in_feb, day = 0; /* calculate time & date to account for out of range values */ if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59) @@ -100,10 +101,12 @@ { res = div (tim_p->tm_hour, 24); tim_p->tm_mday += res.quot; + day = res.quot; if ((tim_p->tm_hour = res.rem) < 0) { tim_p->tm_hour += 24; --tim_p->tm_mday; + --day; } } @@ -118,23 +121,21 @@ } } - if (_DAYS_IN_YEAR (tim_p->tm_year) == 366) - days_in_feb = 29; + days_in_feb = ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? 29 : 28); if (tim_p->tm_mday <= 0) { - while (tim_p->tm_mday <= 0) + do { if (--tim_p->tm_mon == -1) { tim_p->tm_year--; tim_p->tm_mon = 11; - days_in_feb = - ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? - 29 : 28); + days_in_feb = ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? 29 : 28); } tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon); } + while (tim_p->tm_mday <= 0); } else { @@ -145,12 +146,11 @@ { tim_p->tm_year++; tim_p->tm_mon = 0; - days_in_feb = - ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? - 29 : 28); + days_in_feb = ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? 29 : 28); } } } + return day; } time_t @@ -159,7 +159,7 @@ { time_t tim = 0; long days = 0; - int year, isdst=0; + int year, isdst; __tzinfo_type *tz = __gettzinfo (); /* validate structure */ @@ -178,29 +178,23 @@ /* compute day of the year */ tim_p->tm_yday = days; - if (tim_p->tm_year > 10000 - || tim_p->tm_year < -10000) - { - return (time_t) -1; - } + if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000) + return (time_t) -1; /* compute days in other years */ - if (tim_p->tm_year > 70) + year = tim_p->tm_year; + if (year > 70) { for (year = 70; year < tim_p->tm_year; year++) - days += _DAYS_IN_YEAR (year); + days += _DAYS_IN_YEAR (year); } - else if (tim_p->tm_year < 70) + else if (year < 70) { for (year = 69; year > tim_p->tm_year; year--) - days -= _DAYS_IN_YEAR (year); + days -= _DAYS_IN_YEAR (year); days -= _DAYS_IN_YEAR (year); } - /* compute day of the week */ - if ((tim_p->tm_wday = (days + 4) % 7) < 0) - tim_p->tm_wday += 7; - /* compute total seconds */ tim += (days * _SEC_IN_DAY); @@ -208,51 +202,57 @@ if (_daylight) { - int tm_isdst; int y = tim_p->tm_year + YEAR_BASE; - /* Convert user positive into 1 */ - tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst; - isdst = tm_isdst; - if (y == tz->__tzyear || __tzcalc_limits (y)) - { - /* calculate start of dst in dst local time and - start of std in both std local time and dst local time */ - time_t startdst_dst = tz->__tzrule[0].change - - (time_t) tz->__tzrule[1].offset; - time_t startstd_dst = tz->__tzrule[1].change - - (time_t) tz->__tzrule[1].offset; - time_t startstd_std = tz->__tzrule[1].change - - (time_t) tz->__tzrule[0].offset; - /* if the time is in the overlap between dst and std local times */ - if (tim >= startstd_std && tim < startstd_dst) - ; /* we let user decide or leave as -1 */ - else - { - isdst = (tz->__tznorth - ? (tim >= startdst_dst && tim < startstd_std) - : (tim >= startdst_dst || tim < startstd_std)); - /* if user committed and was wrong, perform correction, but not - * if the user has given a negative value (which - * asks mktime() to determine if DST is in effect or not) */ - if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1) - { - /* we either subtract or add the difference between - time zone offsets, depending on which way the user got it - wrong. The diff is typically one hour, or 3600 seconds, - and should fit in a 16-bit int, even though offset - is a long to accomodate 12 hours. */ - int diff = (int) (tz->__tzrule[0].offset - - tz->__tzrule[1].offset); - if (!isdst) - diff = -diff; - tim_p->tm_sec += diff; - validate_structure (tim_p); - tim += diff; /* we also need to correct our current time calculation */ - } - } - } + { + int total_diff = 0; + int diff = (int) (tz->__tzrule[0].offset - tz->__tzrule[1].offset); + isdst = tim_p->tm_isdst; + if (isdst >= 1) { + tim -= diff; + total_diff -= diff; + } + /* startstd = ([1]change = days_in_sec + (start_time = (hms + dst_addin)) + * + ([1]offset = GMT0offset - dst_addin)) - ([0]offset = GMT0offset); + * startstd = days_in_sec + (hms + dst_addin) + (GMT0offset - dst_addin) + * - (GMT0offset); + * startstd = days_in_sec + hms; + * all dst converted to std, and <0 makes time as std. */ + time_t startstd = tz->__tzrule[1].change - (time_t) tz->__tzrule[0].offset; + time_t startdst = tz->__tzrule[0].change - (time_t) tz->__tzrule[0].offset; + isdst = 0; + if (((tz->__tznorth) && (tim >= startdst && tim < startstd)) + || (!(tz->__tznorth) && (tim >= startdst || tim < startstd))) + { + tim += diff; + total_diff += diff; + isdst = 1; + } + if (total_diff) + { + tim_p->tm_sec += total_diff; + if ((diff = validate_structure (tim_p))) + { + days += diff; + if ((tim_p->tm_yday += diff) < 0) + { + --year; + tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1; + } + else + { + diff = _DAYS_IN_YEAR(year); + if (tim_p->tm_yday > (diff - 1)) + tim_p->tm_yday -= diff; + } + } + } + } + else + isdst = -1; } + else + isdst = 0; /* add appropriate offset to put time in gmt format */ if (isdst == 1) @@ -265,5 +265,9 @@ /* reset isdst flag to what we have calculated */ tim_p->tm_isdst = isdst; + /* compute day of the week */ + if ((tim_p->tm_wday = (days + 4) % 7) < 0) + tim_p->tm_wday += 7; + return tim; }