diff -ru php-5.2.6/ext/date/lib/tm2unixtime.c php-5.2.6-patched/ext/date/lib/tm2unixtime.c --- php-5.2.6/ext/date/lib/tm2unixtime.c 2008-01-27 03:26:47.000000000 +1100 +++ php-5.2.6-patched/ext/date/lib/tm2unixtime.c 2008-08-23 03:21:11.000000000 +1000 @@ -25,63 +25,66 @@ static int month_tab[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* dec jan feb mrt apr may jun jul aug sep oct nov dec */ -static int days_in_month_leap[13] = { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -static int days_in_month[13] = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +/*static int days_in_month_leap[13] = { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };*/ +static int days_in_month[13] = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -static int do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b) +void do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b) { + /* note: adj = end - start, it's redundant */ if (*a < start) { - *a += adj; - (*b)--; - return 1; - } - if (*a >= end) { - if (start == 0) { - (*b) += (*a / end); - (*a) -= (end * (*a / end)); - return 0; + /* b -= ceiling((start-a)/adj) */ + *b -= (start - *a - 1) / adj + 1; + /* Modulo normalization for a. + * We use "start - a" instead of "a - start" because modulos must have + * positive operands + */ + *a = start - ((start - *a) % adj); + if (*a < start) { + *a += adj; } - - *a -= adj; - (*b)++; - return 1; + } else if (*a >= end) { + /* b += ceiling((a-(end-1))/adj) */ + *b += (*a - end) / adj + 1; + /* Modulo normalization for a */ + *a = (*a - start) % adj + start; } - return 0; } -static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d) +void do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d) { - timelib_sll leapyear; - timelib_sll days_this_month; - timelib_sll last_month, last_year; - timelib_sll days_last_month; + timelib_sll jd, jd_a, jd_b, jd_c, jd_d, jd_e, jd_m, jd_y; - do_range_limit(1, 13, 12, m, y); - - leapyear = timelib_is_leap(*y); - days_this_month = leapyear ? days_in_month_leap[*m] : days_in_month[*m]; - last_month = (*m) - 1; - - if (last_month < 1) { - last_month += 12; - last_year = (*y) - 1; - } else { - last_year = (*y); + /* Common-case optimization -- day within non-leap limits */ + if (*m >= 1 && *m <= 12 && *d >= 1 && *d <= days_in_month[*m]) { + return; } - leapyear = timelib_is_leap(last_year); - days_last_month = leapyear ? days_in_month_leap[last_month] : days_in_month[last_month]; - if (*d <= 0) { - *d += days_last_month; - (*m)--; - return 1; - } - if (*d > days_this_month) { - *d -= days_this_month; - (*m)++; - return 1; - } - return 0; + /* Normalize month */ + do_range_limit(1, 13, 12, m, y); + + /* + * Calculate Julian day, using the method in Claus Tøndering's FAQ: + * http://www.tondering.dk/claus/cal/node3.html + * Note that the structure of the formula is such that *d does not need + * to be pre-normalized + */ + jd_a = (14 - *m) / 12; + jd_y = *y + 4800 - jd_a; + jd_m = *m + 12 * jd_a - 3; + jd = *d + (153 * jd_m + 2) / 5 + 365 * jd_y + (jd_y/4) - (jd_y/100) + (jd_y/400) - 32045; + + /* + * Convert back to y/m/d (ibid.) + */ + jd_a = jd + 32044; + jd_b = (4 * jd_a + 3) / 146097; + jd_c = jd_a - (146097 * jd_b) / 4; + jd_d = (4 * jd_c + 3) / 1461; + jd_e = jd_c - (1461 * jd_d) / 4; + jd_m = (5 * jd_e + 2) / 153; + *d = jd_e - (153 * jd_m + 2) / 5 + 1; + *m = jd_m + 3 - 12 * (jd_m / 10); + *y = 100 * jd_b + jd_d - 4800 + (jd_m / 10); } static void do_adjust_for_weekday(timelib_time* time) @@ -103,13 +106,13 @@ static void do_normalize(timelib_time* time) { - do {} while (do_range_limit(0, 60, 60, &time->s, &time->i)); - do {} while (do_range_limit(0, 60, 60, &time->i, &time->h)); - do {} while (do_range_limit(0, 24, 24, &time->h, &time->d)); - do {} while (do_range_limit(1, 13, 12, &time->m, &time->y)); + do_range_limit(0, 60, 60, &time->s, &time->i); + do_range_limit(0, 60, 60, &time->i, &time->h); + do_range_limit(0, 24, 24, &time->h, &time->d); + do_range_limit(1, 13, 12, &time->m, &time->y); - do {} while (do_range_limit_days(&time->y, &time->m, &time->d)); - do {} while (do_range_limit(1, 13, 12, &time->m, &time->y)); + do_range_limit_days(&time->y, &time->m, &time->d); + do_range_limit(1, 13, 12, &time->m, &time->y); } static void do_adjust_relative(timelib_time* time)