Skip to content

Commit d9c8e5a

Browse files
committed
Fixed bug #80963: DateTimeZone::getTransitions() truncated
1 parent 66ea59e commit d9c8e5a

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ PHP NEWS
44

55
- Date:
66
. Fixed bug #79580 (date_create_from_format misses leap year). (Derick)
7+
. Fixed bug #80963 (DateTimeZone::getTransitions() truncated). (Derick)
78
. Fixed bug #80974 (Wrong diff between 2 dates in different timezones).
89
(Derick)
910
. Fixed bug #80998 (Missing second with inverted interval). (Derick)

ext/date/php_date.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3591,7 +3591,7 @@ PHP_FUNCTION(timezone_transitions_get)
35913591
zval *object, element;
35923592
php_timezone_obj *tzobj;
35933593
unsigned int begin = 0, found;
3594-
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = ZEND_LONG_MAX;
3594+
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = INT32_MAX;
35953595

35963596
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
35973597
RETURN_THROWS();
@@ -3658,6 +3658,35 @@ PHP_FUNCTION(timezone_transitions_get)
36583658
for (i = begin; i < tzobj->tzi.tz->bit64.timecnt; ++i) {
36593659
if (tzobj->tzi.tz->trans[i] < timestamp_end) {
36603660
add(i, tzobj->tzi.tz->trans[i]);
3661+
} else {
3662+
return;
3663+
}
3664+
}
3665+
if (tzobj->tzi.tz->posix_info && tzobj->tzi.tz->posix_info->dst_end) {
3666+
int i, j;
3667+
timelib_sll start_y, end_y, dummy_m, dummy_d;
3668+
timelib_sll last_transition_ts = tzobj->tzi.tz->trans[tzobj->tzi.tz->bit64.timecnt - 1];
3669+
3670+
/* Find out year for last transition */
3671+
timelib_unixtime2date(last_transition_ts, &start_y, &dummy_m, &dummy_d);
3672+
3673+
/* Find out year for final boundary timestamp */
3674+
timelib_unixtime2date(timestamp_end, &end_y, &dummy_m, &dummy_d);
3675+
3676+
for (i = start_y; i <= end_y; i++) {
3677+
timelib_posix_transitions transitions = { 0 };
3678+
3679+
timelib_get_transitions_for_year(tzobj->tzi.tz, i, &transitions);
3680+
3681+
for (j = 0; j < transitions.count; j++) {
3682+
if (transitions.times[j] <= last_transition_ts) {
3683+
continue;
3684+
}
3685+
if (transitions.times[j] > timestamp_end) {
3686+
return;
3687+
}
3688+
add(transitions.types[j], transitions.times[j]);
3689+
}
36613690
}
36623691
}
36633692
}

ext/date/tests/bug80963.phpt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
Bug #80963: DateTimeZone::getTransitions() truncated
3+
--INI--
4+
date.timezone=UTC
5+
--FILE--
6+
<?php
7+
$tzids = [ 'Europe/London', 'America/New_York', 'Europe/Berlin' ];
8+
9+
foreach ($tzids as $tzid)
10+
{
11+
$tz = new DateTimeZone($tzid);
12+
$t = $tz->getTransitions();
13+
var_dump(sizeof($t), end($t));
14+
}
15+
?>
16+
--EXPECT--
17+
int(243)
18+
array(5) {
19+
["ts"]=>
20+
int(2140045200)
21+
["time"]=>
22+
string(24) "2037-10-25T01:00:00+0000"
23+
["offset"]=>
24+
int(0)
25+
["isdst"]=>
26+
bool(false)
27+
["abbr"]=>
28+
string(3) "GMT"
29+
}
30+
int(237)
31+
array(5) {
32+
["ts"]=>
33+
int(2140668000)
34+
["time"]=>
35+
string(24) "2037-11-01T06:00:00+0000"
36+
["offset"]=>
37+
int(-18000)
38+
["isdst"]=>
39+
bool(false)
40+
["abbr"]=>
41+
string(3) "EST"
42+
}
43+
int(144)
44+
array(5) {
45+
["ts"]=>
46+
int(2140045200)
47+
["time"]=>
48+
string(24) "2037-10-25T01:00:00+0000"
49+
["offset"]=>
50+
int(3600)
51+
["isdst"]=>
52+
bool(false)
53+
["abbr"]=>
54+
string(3) "CET"
55+
}

0 commit comments

Comments
 (0)