Skip to content

Commit e6c4988

Browse files
committed
Fixed #7752, #8101, #81660: DateTimeZone::getTransitions() returns insufficient data
1 parent 7d6a3af commit e6c4988

File tree

3 files changed

+102
-20
lines changed

3 files changed

+102
-20
lines changed

NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.1.6
44

5+
- Date:
6+
. Fixed bug GH-7752 (DateTimeZone::getTransitions() returns insufficient
7+
data). (Derick)
8+
. Fixed bug GH-8108 (Timezone doesn't work as intended). (Derick)
9+
. Fixed bug #81660 (DateTimeZone::getTransitions() returns invalid data).
10+
(Derick)
511

612
31 Mar 2022, PHP 8.1.5
713

ext/date/php_date.c

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3629,6 +3629,15 @@ PHP_FUNCTION(timezone_transitions_get)
36293629
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
36303630
add_next_index_zval(return_value, &element);
36313631

3632+
#define add_from_tto(to,ts) \
3633+
array_init(&element); \
3634+
add_assoc_long(&element, "ts", ts); \
3635+
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0)); \
3636+
add_assoc_long(&element, "offset", (to)->offset); \
3637+
add_assoc_bool(&element, "isdst", (to)->is_dst); \
3638+
add_assoc_string(&element, "abbr", (to)->abbr); \
3639+
add_next_index_zval(return_value, &element);
3640+
36323641
#define add_last() add(tzobj->tzi.tz->bit64.timecnt - 1, timestamp_begin)
36333642

36343643
array_init(return_value);
@@ -3658,7 +3667,13 @@ PHP_FUNCTION(timezone_transitions_get)
36583667

36593668
if (!found) {
36603669
if (tzobj->tzi.tz->bit64.timecnt > 0) {
3661-
add_last();
3670+
if (tzobj->tzi.tz->posix_info && tzobj->tzi.tz->posix_info->dst_end) {
3671+
timelib_time_offset *tto = timelib_get_time_zone_info(timestamp_begin, tzobj->tzi.tz);
3672+
add_from_tto(tto, timestamp_begin);
3673+
timelib_time_offset_dtor(tto);
3674+
} else {
3675+
add_last();
3676+
}
36623677
} else {
36633678
add_nominal();
36643679
}
@@ -3671,31 +3686,34 @@ PHP_FUNCTION(timezone_transitions_get)
36713686
return;
36723687
}
36733688
}
3674-
if (tzobj->tzi.tz->posix_info && tzobj->tzi.tz->posix_info->dst_end) {
3675-
int i, j;
3676-
timelib_sll start_y, end_y, dummy_m, dummy_d;
3677-
timelib_sll last_transition_ts = tzobj->tzi.tz->trans[tzobj->tzi.tz->bit64.timecnt - 1];
3689+
}
3690+
if (tzobj->tzi.tz->posix_info && tzobj->tzi.tz->posix_info->dst_end) {
3691+
int i, j;
3692+
timelib_sll start_y, end_y, dummy_m, dummy_d;
3693+
timelib_sll last_transition_ts = tzobj->tzi.tz->trans[tzobj->tzi.tz->bit64.timecnt - 1];
36783694

3679-
/* Find out year for last transition */
3680-
timelib_unixtime2date(last_transition_ts, &start_y, &dummy_m, &dummy_d);
3695+
/* Find out year for last transition */
3696+
timelib_unixtime2date(last_transition_ts, &start_y, &dummy_m, &dummy_d);
36813697

3682-
/* Find out year for final boundary timestamp */
3683-
timelib_unixtime2date(timestamp_end, &end_y, &dummy_m, &dummy_d);
3698+
/* Find out year for final boundary timestamp */
3699+
timelib_unixtime2date(timestamp_end, &end_y, &dummy_m, &dummy_d);
36843700

3685-
for (i = start_y; i <= end_y; i++) {
3686-
timelib_posix_transitions transitions = { 0 };
3701+
for (i = start_y; i <= end_y; i++) {
3702+
timelib_posix_transitions transitions = { 0 };
36873703

3688-
timelib_get_transitions_for_year(tzobj->tzi.tz, i, &transitions);
3704+
timelib_get_transitions_for_year(tzobj->tzi.tz, i, &transitions);
36893705

3690-
for (j = 0; j < transitions.count; j++) {
3691-
if (transitions.times[j] <= last_transition_ts) {
3692-
continue;
3693-
}
3694-
if (transitions.times[j] > timestamp_end) {
3695-
return;
3696-
}
3697-
add_by_index(transitions.types[j], transitions.times[j]);
3706+
for (j = 0; j < transitions.count; j++) {
3707+
if (transitions.times[j] <= last_transition_ts) {
3708+
continue;
3709+
}
3710+
if (transitions.times[j] < timestamp_begin) {
3711+
continue;
3712+
}
3713+
if (transitions.times[j] > timestamp_end) {
3714+
return;
36983715
}
3716+
add_by_index(transitions.types[j], transitions.times[j]);
36993717
}
37003718
}
37013719
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
GH-7752: DateTimeZone::getTransitions() does not return enough information
3+
--FILE--
4+
<?php
5+
function showTransitions(string $tzid, int $from)
6+
{
7+
$to = $from + ((2.5 * 366) * 24 * 60 * 60);
8+
9+
echo "{$tzid} from @{$from}-@{$to}:\n\n";
10+
11+
$tz = new DateTimeZone($tzid);
12+
foreach ($tz->getTransitions($from, $to) as $t) {
13+
printf("%12d %s %6d %s %s\n", $t['ts'], $t['time'], $t['offset'], $t['isdst'] ? "DST" : " x ", $t['abbr']);
14+
}
15+
echo "\n";
16+
}
17+
18+
19+
showTransitions('Europe/London', 1648342200);
20+
showTransitions('America/Los_Angeles', 1648557596); // GH Issue 7752
21+
showTransitions('America/Chicago', 1293861600); // PHP Bug 81660
22+
showTransitions('Europe/Paris', 1645095600); // GH Issue 8108
23+
?>
24+
--EXPECT--
25+
Europe/London from @1648342200-@1727398200:
26+
27+
1648342200 2022-03-27T00:50:00+0000 0 x GMT
28+
1648342800 2022-03-27T01:00:00+0000 3600 DST BST
29+
1667091600 2022-10-30T01:00:00+0000 0 x GMT
30+
1679792400 2023-03-26T01:00:00+0000 3600 DST BST
31+
1698541200 2023-10-29T01:00:00+0000 0 x GMT
32+
1711846800 2024-03-31T01:00:00+0000 3600 DST BST
33+
34+
America/Los_Angeles from @1648557596-@1727613596:
35+
36+
1648557596 2022-03-29T12:39:56+0000 -25200 DST PDT
37+
1667725200 2022-11-06T09:00:00+0000 -28800 x PST
38+
1678615200 2023-03-12T10:00:00+0000 -25200 DST PDT
39+
1699174800 2023-11-05T09:00:00+0000 -28800 x PST
40+
1710064800 2024-03-10T10:00:00+0000 -25200 DST PDT
41+
42+
America/Chicago from @1293861600-@1372917600:
43+
44+
1293861600 2011-01-01T06:00:00+0000 -21600 x CST
45+
1300003200 2011-03-13T08:00:00+0000 -18000 DST CDT
46+
1320562800 2011-11-06T07:00:00+0000 -21600 x CST
47+
1331452800 2012-03-11T08:00:00+0000 -18000 DST CDT
48+
1352012400 2012-11-04T07:00:00+0000 -21600 x CST
49+
1362902400 2013-03-10T08:00:00+0000 -18000 DST CDT
50+
51+
Europe/Paris from @1645095600-@1724151600:
52+
53+
1645095600 2022-02-17T11:00:00+0000 3600 x CET
54+
1648342800 2022-03-27T01:00:00+0000 7200 DST CEST
55+
1667091600 2022-10-30T01:00:00+0000 3600 x CET
56+
1679792400 2023-03-26T01:00:00+0000 7200 DST CEST
57+
1698541200 2023-10-29T01:00:00+0000 3600 x CET
58+
1711846800 2024-03-31T01:00:00+0000 7200 DST CEST

0 commit comments

Comments
 (0)