Skip to content

Commit

Permalink
Fixed bug #80963: DateTimeZone::getTransitions() truncated
Browse files Browse the repository at this point in the history
  • Loading branch information
derickr committed Aug 8, 2021
1 parent 66ea59e commit d9c8e5a
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ PHP NEWS

- Date:
. Fixed bug #79580 (date_create_from_format misses leap year). (Derick)
. Fixed bug #80963 (DateTimeZone::getTransitions() truncated). (Derick)
. Fixed bug #80974 (Wrong diff between 2 dates in different timezones).
(Derick)
. Fixed bug #80998 (Missing second with inverted interval). (Derick)
Expand Down
31 changes: 30 additions & 1 deletion ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -3591,7 +3591,7 @@ PHP_FUNCTION(timezone_transitions_get)
zval *object, element;
php_timezone_obj *tzobj;
unsigned int begin = 0, found;
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = ZEND_LONG_MAX;
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = INT32_MAX;

if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
RETURN_THROWS();
Expand Down Expand Up @@ -3658,6 +3658,35 @@ PHP_FUNCTION(timezone_transitions_get)
for (i = begin; i < tzobj->tzi.tz->bit64.timecnt; ++i) {
if (tzobj->tzi.tz->trans[i] < timestamp_end) {
add(i, tzobj->tzi.tz->trans[i]);
} else {
return;
}
}
if (tzobj->tzi.tz->posix_info && tzobj->tzi.tz->posix_info->dst_end) {
int i, j;
timelib_sll start_y, end_y, dummy_m, dummy_d;
timelib_sll last_transition_ts = tzobj->tzi.tz->trans[tzobj->tzi.tz->bit64.timecnt - 1];

/* Find out year for last transition */
timelib_unixtime2date(last_transition_ts, &start_y, &dummy_m, &dummy_d);

/* Find out year for final boundary timestamp */
timelib_unixtime2date(timestamp_end, &end_y, &dummy_m, &dummy_d);

for (i = start_y; i <= end_y; i++) {
timelib_posix_transitions transitions = { 0 };

timelib_get_transitions_for_year(tzobj->tzi.tz, i, &transitions);

for (j = 0; j < transitions.count; j++) {
if (transitions.times[j] <= last_transition_ts) {
continue;
}
if (transitions.times[j] > timestamp_end) {
return;
}
add(transitions.types[j], transitions.times[j]);
}
}
}
}
Expand Down
55 changes: 55 additions & 0 deletions ext/date/tests/bug80963.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--TEST--
Bug #80963: DateTimeZone::getTransitions() truncated
--INI--
date.timezone=UTC
--FILE--
<?php
$tzids = [ 'Europe/London', 'America/New_York', 'Europe/Berlin' ];

foreach ($tzids as $tzid)
{
$tz = new DateTimeZone($tzid);
$t = $tz->getTransitions();
var_dump(sizeof($t), end($t));
}
?>
--EXPECT--
int(243)
array(5) {
["ts"]=>
int(2140045200)
["time"]=>
string(24) "2037-10-25T01:00:00+0000"
["offset"]=>
int(0)
["isdst"]=>
bool(false)
["abbr"]=>
string(3) "GMT"
}
int(237)
array(5) {
["ts"]=>
int(2140668000)
["time"]=>
string(24) "2037-11-01T06:00:00+0000"
["offset"]=>
int(-18000)
["isdst"]=>
bool(false)
["abbr"]=>
string(3) "EST"
}
int(144)
array(5) {
["ts"]=>
int(2140045200)
["time"]=>
string(24) "2037-10-25T01:00:00+0000"
["offset"]=>
int(3600)
["isdst"]=>
bool(false)
["abbr"]=>
string(3) "CET"
}

0 comments on commit d9c8e5a

Please sign in to comment.