Skip to content

Commit 5042be1

Browse files
committed
Fix GH-#18051 (DateTimeZone->getTransitions can return first transition twice)
1 parent 4122daa commit 5042be1

File tree

2 files changed

+118
-15
lines changed

2 files changed

+118
-15
lines changed

ext/date/php_date.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4265,6 +4265,7 @@ PHP_FUNCTION(timezone_transitions_get)
42654265
uint64_t begin = 0;
42664266
bool found;
42674267
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = INT32_MAX;
4268+
zend_long timestamp_added_last = ZEND_LONG_MIN;
42684269

42694270
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
42704271
RETURN_THROWS();
@@ -4282,25 +4283,32 @@ PHP_FUNCTION(timezone_transitions_get)
42824283
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[0].offset); \
42834284
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[0].isdst); \
42844285
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx]); \
4285-
add_next_index_zval(return_value, &element);
4286+
add_next_index_zval(return_value, &element); \
4287+
timestamp_added_last = timestamp_begin;
42864288

42874289
#define add(i,ts) \
4288-
array_init_size(&element, 5); \
4289-
add_assoc_long(&element, "ts", ts); \
4290-
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4291-
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
4292-
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
4293-
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
4294-
add_next_index_zval(return_value, &element);
4290+
if (ts > timestamp_added_last) { \
4291+
array_init_size(&element, 5); \
4292+
add_assoc_long(&element, "ts", ts); \
4293+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4294+
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
4295+
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
4296+
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
4297+
add_next_index_zval(return_value, &element); \
4298+
timestamp_added_last = ts; \
4299+
}
42954300

42964301
#define add_by_index(i,ts) \
4297-
array_init_size(&element, 5); \
4298-
add_assoc_long(&element, "ts", ts); \
4299-
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4300-
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[i].offset); \
4301-
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[i].isdst); \
4302-
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
4303-
add_next_index_zval(return_value, &element);
4302+
if (ts > timestamp_added_last) { \
4303+
array_init_size(&element, 5); \
4304+
add_assoc_long(&element, "ts", ts); \
4305+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4306+
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[i].offset); \
4307+
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[i].isdst); \
4308+
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
4309+
add_next_index_zval(return_value, &element); \
4310+
timestamp_added_last = ts; \
4311+
}
43044312

43054313
#define add_from_tto(to,ts) \
43064314
array_init_size(&element, 5); \

ext/date/tests/gh18051.phpt

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
--TEST--
2+
Bug GH-18051 (DateTimeZone->getTransitions can return first transition twice)
3+
--FILE--
4+
<?php
5+
6+
$tzBln = new DateTimeZone('Europe/Berlin');
7+
var_dump($tzBln->getTransitions(922582799, 941331599));
8+
var_dump($tzBln->getTransitions(922582800, 941331600));
9+
var_dump($tzBln->getTransitions(922582801, 941331601));
10+
11+
--EXPECT--
12+
array(2) {
13+
[0]=>
14+
array(5) {
15+
["ts"]=>
16+
int(922582799)
17+
["time"]=>
18+
string(25) "1999-03-28T00:59:59+00:00"
19+
["offset"]=>
20+
int(3600)
21+
["isdst"]=>
22+
bool(false)
23+
["abbr"]=>
24+
string(3) "CET"
25+
}
26+
[1]=>
27+
array(5) {
28+
["ts"]=>
29+
int(922582800)
30+
["time"]=>
31+
string(25) "1999-03-28T01:00:00+00:00"
32+
["offset"]=>
33+
int(7200)
34+
["isdst"]=>
35+
bool(true)
36+
["abbr"]=>
37+
string(4) "CEST"
38+
}
39+
}
40+
array(2) {
41+
[0]=>
42+
array(5) {
43+
["ts"]=>
44+
int(922582800)
45+
["time"]=>
46+
string(25) "1999-03-28T01:00:00+00:00"
47+
["offset"]=>
48+
int(7200)
49+
["isdst"]=>
50+
bool(true)
51+
["abbr"]=>
52+
string(4) "CEST"
53+
}
54+
[1]=>
55+
array(5) {
56+
["ts"]=>
57+
int(941331600)
58+
["time"]=>
59+
string(25) "1999-10-31T01:00:00+00:00"
60+
["offset"]=>
61+
int(3600)
62+
["isdst"]=>
63+
bool(false)
64+
["abbr"]=>
65+
string(3) "CET"
66+
}
67+
}
68+
array(2) {
69+
[0]=>
70+
array(5) {
71+
["ts"]=>
72+
int(922582801)
73+
["time"]=>
74+
string(25) "1999-03-28T01:00:01+00:00"
75+
["offset"]=>
76+
int(7200)
77+
["isdst"]=>
78+
bool(true)
79+
["abbr"]=>
80+
string(4) "CEST"
81+
}
82+
[1]=>
83+
array(5) {
84+
["ts"]=>
85+
int(941331600)
86+
["time"]=>
87+
string(25) "1999-10-31T01:00:00+00:00"
88+
["offset"]=>
89+
int(3600)
90+
["isdst"]=>
91+
bool(false)
92+
["abbr"]=>
93+
string(3) "CET"
94+
}
95+
}

0 commit comments

Comments
 (0)