Skip to content

Commit c3df98b

Browse files
committed
Fix GH-php#18051 (DateTimeZone->getTransitions can return first transition twice)
1 parent cd58662 commit c3df98b

File tree

2 files changed

+128
-22
lines changed

2 files changed

+128
-22
lines changed

ext/date/php_date.c

+33-22
Original file line numberDiff line numberDiff line change
@@ -4273,6 +4273,7 @@ PHP_FUNCTION(timezone_transitions_get)
42734273
uint64_t begin = 0;
42744274
bool found;
42754275
zend_long timestamp_begin = ZEND_LONG_MIN, timestamp_end = INT32_MAX;
4276+
zend_long timestamp_added_last = ZEND_LONG_MIN;
42764277

42774278
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
42784279
RETURN_THROWS();
@@ -4290,34 +4291,44 @@ PHP_FUNCTION(timezone_transitions_get)
42904291
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[0].offset); \
42914292
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[0].isdst); \
42924293
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx]); \
4293-
add_next_index_zval(return_value, &element);
4294+
add_next_index_zval(return_value, &element); \
4295+
timestamp_added_last = timestamp_begin;
42944296

42954297
#define add(i,ts) \
4296-
array_init(&element); \
4297-
add_assoc_long(&element, "ts", ts); \
4298-
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4299-
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
4300-
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
4301-
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
4302-
add_next_index_zval(return_value, &element);
4298+
if (timestamp_added_last != ts) { \
4299+
array_init(&element); \
4300+
add_assoc_long(&element, "ts", ts); \
4301+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4302+
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
4303+
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
4304+
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
4305+
add_next_index_zval(return_value, &element); \
4306+
timestamp_added_last = ts; \
4307+
}
43034308

43044309
#define add_by_index(i,ts) \
4305-
array_init(&element); \
4306-
add_assoc_long(&element, "ts", ts); \
4307-
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4308-
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[i].offset); \
4309-
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[i].isdst); \
4310-
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
4311-
add_next_index_zval(return_value, &element);
4310+
if (timestamp_added_last != ts) { \
4311+
array_init(&element); \
4312+
add_assoc_long(&element, "ts", ts); \
4313+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4314+
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[i].offset); \
4315+
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[i].isdst); \
4316+
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
4317+
add_next_index_zval(return_value, &element); \
4318+
timestamp_added_last = ts; \
4319+
}
43124320

43134321
#define add_from_tto(to,ts) \
4314-
array_init(&element); \
4315-
add_assoc_long(&element, "ts", ts); \
4316-
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4317-
add_assoc_long(&element, "offset", (to)->offset); \
4318-
add_assoc_bool(&element, "isdst", (to)->is_dst); \
4319-
add_assoc_string(&element, "abbr", (to)->abbr); \
4320-
add_next_index_zval(return_value, &element);
4322+
if (timestamp_added_last != ts) { \
4323+
array_init(&element); \
4324+
add_assoc_long(&element, "ts", ts); \
4325+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
4326+
add_assoc_long(&element, "offset", (to)->offset); \
4327+
add_assoc_bool(&element, "isdst", (to)->is_dst); \
4328+
add_assoc_string(&element, "abbr", (to)->abbr); \
4329+
add_next_index_zval(return_value, &element); \
4330+
timestamp_added_last = ts; \
4331+
}
43214332

43224333
#define add_last() add(tzobj->tzi.tz->bit64.timecnt - 1, timestamp_begin)
43234334

ext/date/tests/gh18051.phpt

+95
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)