Skip to content

Commit 50d8d86

Browse files
committed
ext/date: trim and expand DST tests for GH-21616 and GH-15880
Remove section headers and redundant cases. Add -72h backward through fall-back, +61 minutes across spring-forward gap, and DateTimeImmutable.
1 parent 03ff333 commit 50d8d86

2 files changed

Lines changed: 32 additions & 83 deletions

File tree

ext/date/tests/gh15880.phpt

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,26 @@ Bug GH-15880 (DateTime::modify('+72 hours') incorrect across DST boundary)
33
--FILE--
44
<?php
55
/* Fall back: America/Chicago, 2024-11-03 02:00 CDT -> 01:00 CST.
6-
* +72 hours from 2024-11-01 00:00 CDT must be 2024-11-03 23:00 CST,
7-
* not 2024-11-04 00:00 CST. */
6+
* +72 hours from midnight Nov 1 must land at Nov 3 23:00 CST, not Nov 4 00:00. */
7+
date_default_timezone_set('America/Chicago');
88
$tz = new DateTimeZone('America/Chicago');
9-
10-
echo "=== Fall back (explicit timezone) ===\n";
11-
129
$start = new DateTimeImmutable('2024-11-01 00:00:00', $tz);
1310

14-
echo "modify +72 hours:\n";
11+
/* modify and add must agree */
1512
echo $start->modify('+72 hours')->format('Y-m-d H:i:s T U'), "\n";
13+
echo $start->add(new DateInterval('PT72H'))->format('Y-m-d H:i:s T U'), "\n";
1614

17-
echo "add PT72H (reference):\n";
18-
echo $start->add(new DateInterval('PT72H'))
19-
->format('Y-m-d H:i:s T U'), "\n";
20-
21-
echo "\n=== Fall back with default timezone ===\n";
22-
23-
/* Exact reproduction from GH-15880: date_default_timezone_set,
24-
* DateTimeImmutable, +72 hour via modify vs add. Also test that
25-
* +3 days (calendar arithmetic) is unaffected — it should land on
26-
* midnight Nov 4, not Nov 3 23:00. */
27-
date_default_timezone_set('America/Chicago');
28-
$start2 = new DateTimeImmutable('2024-11-01');
15+
/* +3 days is calendar arithmetic -- it should land on midnight Nov 4 */
16+
echo $start->modify('+3 days')->format('Y-m-d H:i:s T U'), "\n";
2917

30-
echo "modify +72 hour:\n";
31-
echo $start2->modify('+72 hour')
32-
->format('Y-m-d H:i:s T U'), "\n";
33-
34-
echo "add PT72H (reference):\n";
35-
echo $start2->add(new DateInterval('PT72H'))
36-
->format('Y-m-d H:i:s T U'), "\n";
37-
38-
echo "modify +3 days (calendar, not hours):\n";
39-
echo $start2->modify('+3 days')
40-
->format('Y-m-d H:i:s T U'), "\n";
18+
/* -72 hours backward through fall-back: 73 real hours separate Nov 1 00:00 CDT
19+
* from Nov 4 00:00 CST (the extra hour is the repeated hour), so -72h lands 1h
20+
* ahead of Nov 1 midnight */
21+
$end = new DateTimeImmutable('2024-11-04 00:00:00', $tz);
22+
echo $end->modify('-72 hours')->format('Y-m-d H:i:s T U'), "\n";
4123
?>
4224
--EXPECT--
43-
=== Fall back (explicit timezone) ===
44-
modify +72 hours:
45-
2024-11-03 23:00:00 CST 1730696400
46-
add PT72H (reference):
47-
2024-11-03 23:00:00 CST 1730696400
48-
49-
=== Fall back with default timezone ===
50-
modify +72 hour:
5125
2024-11-03 23:00:00 CST 1730696400
52-
add PT72H (reference):
5326
2024-11-03 23:00:00 CST 1730696400
54-
modify +3 days (calendar, not hours):
5527
2024-11-04 00:00:00 CST 1730700000
28+
2024-11-01 01:00:00 CDT 1730440800

ext/date/tests/gh21616.phpt

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,41 @@
22
Bug GH-21616 (DateTime::modify() does not respect DST transitions)
33
--FILE--
44
<?php
5-
/* Spring forward: Europe/London, 2025-03-30 01:00 GMT -> 02:00 BST.
6-
* Subtracting 1 second from 02:00:00 BST must land at 00:59:59 GMT,
7-
* not at 02:59:59 BST. */
5+
/* Spring forward: Europe/London, 2025-03-30 01:00 GMT -> 02:00 BST */
86
$tz = new DateTimeZone('Europe/London');
97

10-
echo "=== Spring forward ===\n";
11-
12-
echo "modify +1s then -1s:\n";
8+
/* +1s then -1s must round-trip */
139
$dt = new DateTime('2025-03-30 00:59:59', $tz);
1410
$dt->modify('+1 second');
1511
$dt->modify('-1 second');
1612
echo $dt->format('Y-m-d H:i:s T U'), "\n";
1713

18-
echo "add/sub PT1S (reference):\n";
19-
$dt2 = new DateTime('2025-03-30 00:59:59', $tz);
20-
$dt2->add(new DateInterval('PT1S'));
21-
$dt2->sub(new DateInterval('PT1S'));
22-
echo $dt2->format('Y-m-d H:i:s T U'), "\n";
23-
24-
echo "modify -1s from 02:00 BST:\n";
25-
$dt3 = new DateTime('2025-03-30 02:00:00', $tz);
26-
echo $dt3->modify('-1 second')->format('Y-m-d H:i:s T U'), "\n";
14+
/* -1s from 02:00 BST must land at 00:59:59 GMT, not 02:59:59 BST */
15+
$dt2 = new DateTime('2025-03-30 02:00:00', $tz);
16+
echo $dt2->modify('-1 second')->format('Y-m-d H:i:s T U'), "\n";
2717

28-
echo "\n=== Combined relative (month + hours near DST) ===\n";
18+
/* month + hours: +1 month lands before the DST boundary, so +1 hour is plain GMT */
19+
$dt3 = new DateTime('2025-02-28 00:30:00', $tz);
20+
echo $dt3->modify('+1 month +1 hour')->format('Y-m-d H:i:s T U'), "\n";
2921

30-
/* 2025-02-28 00:30:00 GMT + 1 month + 1 hour should land on
31-
* 2025-03-28 01:30:00 GMT (not affected by DST on March 30). */
32-
$dt4 = new DateTime('2025-02-28 00:30:00', $tz);
33-
echo "modify +1 month +1 hour:\n";
34-
echo $dt4->modify('+1 month +1 hour')->format('Y-m-d H:i:s T U'), "\n";
22+
/* first/last day of must still work */
23+
$base = new DateTimeImmutable('2025-03-15 10:00:00', $tz);
24+
echo $base->modify('first day of next month')->format('Y-m-d H:i:s T'), "\n";
25+
echo $base->modify('last day of this month')->format('Y-m-d H:i:s T'), "\n";
3526

36-
echo "\n=== first/last day of (must not regress) ===\n";
27+
/* +61 minutes from just before the gap -- minutes must also count as elapsed time */
28+
$dt4 = new DateTime('2025-03-30 00:59:00', $tz);
29+
echo $dt4->modify('+61 minutes')->format('Y-m-d H:i:s T U'), "\n";
3730

38-
/* Ensure first_last_day_of still works correctly. */
39-
$dt5 = new DateTime('2025-03-15 10:00:00', $tz);
40-
echo "modify first day of next month:\n";
41-
echo $dt5->modify('first day of next month')
42-
->format('Y-m-d H:i:s T'), "\n";
43-
44-
$dt6 = new DateTime('2025-03-15 10:00:00', $tz);
45-
echo "modify last day of this month:\n";
46-
echo $dt6->modify('last day of this month')
47-
->format('Y-m-d H:i:s T'), "\n";
31+
/* DateTimeImmutable must behave the same as mutable DateTime */
32+
$dt5 = new DateTimeImmutable('2025-03-30 02:00:00', $tz);
33+
echo $dt5->modify('-1 second')->format('Y-m-d H:i:s T U'), "\n";
4834
?>
4935
--EXPECT--
50-
=== Spring forward ===
51-
modify +1s then -1s:
52-
2025-03-30 00:59:59 GMT 1743296399
53-
add/sub PT1S (reference):
5436
2025-03-30 00:59:59 GMT 1743296399
55-
modify -1s from 02:00 BST:
5637
2025-03-30 00:59:59 GMT 1743296399
57-
58-
=== Combined relative (month + hours near DST) ===
59-
modify +1 month +1 hour:
6038
2025-03-28 01:30:00 GMT 1743125400
61-
62-
=== first/last day of (must not regress) ===
63-
modify first day of next month:
6439
2025-04-01 10:00:00 BST
65-
modify last day of this month:
6640
2025-03-31 10:00:00 BST
41+
2025-03-30 03:00:00 BST 1743300000
42+
2025-03-30 00:59:59 GMT 1743296399

0 commit comments

Comments
 (0)