From 20b6fee9a41456f157cdf96d80142fb7a5406576 Mon Sep 17 00:00:00 2001 From: Louis-Arnaud Date: Thu, 3 Sep 2026 14:48:32 +0200 Subject: [PATCH 1/4] Unwrap examples and lists from para in the DateTime reference An example, a variablelist or a simplelist that is alone in a para should be a direct child of its container. --- .../dateinterval/createfromdatestring.xml | 92 ++++++++--------- reference/datetime/examples.xml | 98 +++++++++---------- 2 files changed, 88 insertions(+), 102 deletions(-) diff --git a/reference/datetime/dateinterval/createfromdatestring.xml b/reference/datetime/dateinterval/createfromdatestring.xml index 886cac0d345b..cc41421cc2cf 100644 --- a/reference/datetime/dateinterval/createfromdatestring.xml +++ b/reference/datetime/dateinterval/createfromdatestring.xml @@ -28,26 +28,24 @@ &reftitle.parameters; - - - - datetime - - - A date with relative parts. Specifically, the - relative formats supported - by the parser used for DateTimeImmutable, - DateTime, and strtotime - will be used to construct the DateInterval. - - - To use an ISO-8601 format string like P7D, you must - use the DateInterval::__construct. - - - - - + + + datetime + + + A date with relative parts. Specifically, the + relative formats supported + by the parser used for DateTimeImmutable, + DateTime, and strtotime + will be used to construct the DateInterval. + + + To use an ISO-8601 format string like P7D, you must + use the DateInterval::__construct. + + + + @@ -110,10 +108,9 @@ &reftitle.examples; - - - Parsing valid date intervals - + + Parsing valid date intervals + - - - - - - Parsing combinations and negative intervals - + + + + Parsing combinations and negative intervals + format('%d %h %i'), "\n"; $i = DateInterval::createFromDateString('1 year - 10 days'); echo $i->format('%y %d'), "\n"; ]]> - - &example.outputs; - + + &example.outputs; + - - - - - - Parsing special relative date intervals - + + + + Parsing special relative date intervals + - - &example.outputs.82; - + + &example.outputs.82; + @@ -192,9 +185,9 @@ object(DateInterval)#2 (2) { string(12) "last weekday" } ]]> - - &example.outputs.8.similar; - + + &example.outputs.8.similar; + @@ -265,9 +258,8 @@ object(DateInterval)#2 (16) { int(1) } ]]> - - - + + diff --git a/reference/datetime/examples.xml b/reference/datetime/examples.xml index c58489eabed7..61171d0b529b 100644 --- a/reference/datetime/examples.xml +++ b/reference/datetime/examples.xml @@ -10,14 +10,13 @@ The following examples show some pitfalls of Date/Time arithmetic with regard to DST transitions and months having different numbers of days. - - - DateTimeImmutable::add/sub add intervals which cover elapsed time - - Adding PT24H over a DST transition will appear to add 23/25 hours (for - most timezones). - - + + DateTimeImmutable::add/sub add intervals which cover elapsed time + + Adding PT24H over a DST transition will appear to add 23/25 hours (for + most timezones). + + format("Y-m-d H:i:s P"), PHP_EOL; $dt = $dt->add(new DateInterval("PT3H")); echo "End: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL; ]]> - - &example.outputs; - + + &example.outputs; + - - - - - - DateTimeImmutable::modify and strtotime increment or decrement individual component values - - Adding +24 hours over a DST transition will add exactly 24 hours as seen in - the date/time string (unless the start or end time is on a transition - point). - - + + + + DateTimeImmutable::modify and strtotime increment or decrement individual component values + + Adding +24 hours over a DST transition will add exactly 24 hours as seen in + the date/time string (unless the start or end time is on a transition + point). + + format("Y-m-d H:i:s P"), PHP_EOL; $dt = $dt->modify("+24 hours"); echo "End: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL; ]]> - - &example.outputs; - + + &example.outputs; + - - - - - - Adding or subtracting times can over- or underflow dates - - Like where January 31st + 1 month will result in March 2nd (leap year) or - 3rd (normal year). - - + + + + Adding or subtracting times can over- or underflow dates + + Like where January 31st + 1 month will result in March 2nd (leap year) or + 3rd (normal year). + + format("Y-m-d H:i:s P"), PHP_EOL; $dt = $dt->modify("+1 month"); echo "End: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL; ]]> - - &example.outputs; - + + &example.outputs; + - - - To get the last day of the next month (i.e. to prevent the overflow), - the last day of format is available. - - + + + To get the last day of the next month (i.e. to prevent the overflow), + the last day of format is available. + + format("Y-m-d H:i:s P"), PHP_EOL; $dt = $dt->modify("last day of next month"); echo "End: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL; ]]> - - &example.outputs; - + + &example.outputs; + - - - + + From 261bbc4d9d69590512c44dee288ca7aa3efd3d63 Mon Sep 17 00:00:00 2001 From: Louis-Arnaud Date: Thu, 3 Sep 2026 14:49:08 +0200 Subject: [PATCH 2/4] Document that DateInterval addition depends on how the interval was made DateTimeImmutable::add and DateTime::add apply an interval in one of two ways, picked from how the interval was created rather than from what it holds: new DateInterval('PT24H') -> elapsed time DateInterval::createFromDateString('24 hours') -> component values DateTimeInterface::diff() -> component values The two agree on any ordinary day and differ by an hour across a DST transition, which is not documented anywhere. The example on the DateInterval::createFromDateString page stated the opposite outright ("Each set of intervals is equal."). Add a third example to the Date/Time Arithmetic page contrasting the two, state the rule on the DateInterval class page, note it where the equality was claimed, and link the arithmetic page from DateTimeImmutable::add/sub. Output verified on PHP 8.5.4. --- reference/datetime/dateinterval.xml | 11 ++++++++ .../dateinterval/createfromdatestring.xml | 20 ++++++++++---- reference/datetime/datetimeimmutable/add.xml | 1 + reference/datetime/datetimeimmutable/sub.xml | 1 + reference/datetime/examples.xml | 27 +++++++++++++++++++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/reference/datetime/dateinterval.xml b/reference/datetime/dateinterval.xml index 1b6fdeed4798..921def479644 100644 --- a/reference/datetime/dateinterval.xml +++ b/reference/datetime/dateinterval.xml @@ -28,6 +28,17 @@ is by calculating the difference between two date/time objects through DateTimeInterface::diff. + + How an interval is applied when it is added to, or subtracted from, a + date/time object depends on how the interval was created. An interval + created with DateInterval::__construct covers + elapsed time, whereas an interval created with + DateInterval::createFromDateString, or returned + by DateTimeInterface::diff, increments or + decrements the individual component values. The two only give a different + result when a timezone transition falls within the interval; see + Date/Time Arithmetic. + Since there is no well defined way to compare date intervals, DateInterval instances are diff --git a/reference/datetime/dateinterval/createfromdatestring.xml b/reference/datetime/dateinterval/createfromdatestring.xml index cc41421cc2cf..31201ed39a4f 100644 --- a/reference/datetime/dateinterval/createfromdatestring.xml +++ b/reference/datetime/dateinterval/createfromdatestring.xml @@ -32,17 +32,17 @@ datetime - + A date with relative parts. Specifically, the relative formats supported by the parser used for DateTimeImmutable, DateTime, and strtotime will be used to construct the DateInterval. - - + + To use an ISO-8601 format string like P7D, you must use the DateInterval::__construct. - + @@ -113,7 +113,7 @@ + + + Intervals in a set are not interchangeable when they are added to a + date/time object across a timezone transition: an interval created with + DateInterval::__construct covers elapsed time, + whereas an interval created with this method increments or decrements the + individual component values. See + Date/Time Arithmetic. + + Parsing combinations and negative intervals diff --git a/reference/datetime/datetimeimmutable/add.xml b/reference/datetime/datetimeimmutable/add.xml index 5d2595cb0a74..7715645771b4 100644 --- a/reference/datetime/datetimeimmutable/add.xml +++ b/reference/datetime/datetimeimmutable/add.xml @@ -117,6 +117,7 @@ echo $newDate2->format('Y-m-d') . "\n"; DateTimeImmutable::sub DateTimeImmutable::diff DateTimeImmutable::modify + Date/Time Arithmetic diff --git a/reference/datetime/datetimeimmutable/sub.xml b/reference/datetime/datetimeimmutable/sub.xml index 8b4c2f66a6f4..6ed595a4fed7 100644 --- a/reference/datetime/datetimeimmutable/sub.xml +++ b/reference/datetime/datetimeimmutable/sub.xml @@ -155,6 +155,7 @@ echo $newDate2->format('Y-m-d') . "\n"; DateTimeImmutable::add DateTimeImmutable::diff DateTimeImmutable::modify + Date/Time Arithmetic diff --git a/reference/datetime/examples.xml b/reference/datetime/examples.xml index 61171d0b529b..80f8cc0e72db 100644 --- a/reference/datetime/examples.xml +++ b/reference/datetime/examples.xml @@ -54,6 +54,33 @@ echo "End: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL; + + + + DateInterval::createFromDateString creates intervals which increment or decrement component values + + DateInterval::createFromDateString uses the + date/time parser, and the resulting interval increments or decrements the + individual component values. Only an interval created with + DateInterval::__construct covers elapsed time, so + the two are not interchangeable across a timezone transition. + + +format("Y-m-d H:i:s P"), PHP_EOL; +echo "PT24H: ", $dt->add(new DateInterval("PT24H"))->format("Y-m-d H:i:s P"), PHP_EOL; +echo "24 hours: ", $dt->add(DateInterval::createFromDateString("24 hours"))->format("Y-m-d H:i:s P"), PHP_EOL; +]]> + + &example.outputs; + + From 4cbef98d6f4915d623aeb42c4e69d9c61dc01def Mon Sep 17 00:00:00 2001 From: Louis-Arnaud Date: Thu, 3 Sep 2026 15:13:35 +0200 Subject: [PATCH 3/4] Scope the elapsed-time wording to the time part of the interval Only the time part of an interval (hours, minutes, seconds, microseconds) is applied as elapsed time when the interval comes from DateInterval::__construct. The date part goes through the same calendar arithmetic in both cases, so P1D and '1 day' never diverge: 2015-11-01 00:00:00 -04:00 America/New_York + P1D -> 2015-11-02 00:00:00 -05:00 + 1 day -> 2015-11-02 00:00:00 -05:00 Over 400 days of hourly start times, PT24H and '24 hours' diverge 46 times while P1D and '1 day' never do. Of the seven sets listed in the first createFromDateString example, only the two carrying a time part can diverge at all. --- reference/datetime/dateinterval.xml | 17 ++++++++++------- .../dateinterval/createfromdatestring.xml | 12 +++++++----- reference/datetime/examples.xml | 11 +++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/reference/datetime/dateinterval.xml b/reference/datetime/dateinterval.xml index 921def479644..59d9eff0791c 100644 --- a/reference/datetime/dateinterval.xml +++ b/reference/datetime/dateinterval.xml @@ -29,14 +29,17 @@ DateTimeInterface::diff. - How an interval is applied when it is added to, or subtracted from, a - date/time object depends on how the interval was created. An interval - created with DateInterval::__construct covers - elapsed time, whereas an interval created with + How the time part of an interval, that is hours, minutes, seconds and + microseconds, is applied when the interval is added to, or subtracted + from, a date/time object depends on how the interval was created. For an + interval created with DateInterval::__construct + the time part covers elapsed time, whereas for an interval created with DateInterval::createFromDateString, or returned - by DateTimeInterface::diff, increments or - decrements the individual component values. The two only give a different - result when a timezone transition falls within the interval; see + by DateTimeInterface::diff, it increments or + decrements the individual component values. The date part, that is years, + months, weeks and days, always increments or decrements the individual + component values. The two therefore only give a different result when a + timezone transition falls within the time part of the interval; see Date/Time Arithmetic. diff --git a/reference/datetime/dateinterval/createfromdatestring.xml b/reference/datetime/dateinterval/createfromdatestring.xml index 31201ed39a4f..7598a71d0395 100644 --- a/reference/datetime/dateinterval/createfromdatestring.xml +++ b/reference/datetime/dateinterval/createfromdatestring.xml @@ -139,11 +139,13 @@ $i = DateInterval::createFromDateString('3600 seconds'); - Intervals in a set are not interchangeable when they are added to a - date/time object across a timezone transition: an interval created with - DateInterval::__construct covers elapsed time, - whereas an interval created with this method increments or decrements the - individual component values. See + The intervals in a set that have a time part, such as + P1DT12H and 1 day + 12 hours, are + not interchangeable when they are added to a date/time object and a + timezone transition falls within that time part: for an interval created + with DateInterval::__construct the time part + covers elapsed time, whereas for an interval created with this method it + increments or decrements the individual component values. See Date/Time Arithmetic. diff --git a/reference/datetime/examples.xml b/reference/datetime/examples.xml index 80f8cc0e72db..e8139edd67c5 100644 --- a/reference/datetime/examples.xml +++ b/reference/datetime/examples.xml @@ -61,10 +61,13 @@ End: 2015-11-02 00:00:00 -05:00 DateInterval::createFromDateString creates intervals which increment or decrement component values DateInterval::createFromDateString uses the - date/time parser, and the resulting interval increments or decrements the - individual component values. Only an interval created with - DateInterval::__construct covers elapsed time, so - the two are not interchangeable across a timezone transition. + date/time parser, and the time part of the resulting interval increments + or decrements the individual component values. For an interval created + with DateInterval::__construct the time part + covers elapsed time instead, so the two are not interchangeable when a + timezone transition falls within that time part. The date part is applied + the same way by both, so P1D and + 1 day always give the same result. Date: Thu, 3 Sep 2026 16:07:29 +0200 Subject: [PATCH 4/4] Drop weeks from the list of date components DateInterval has no week component: new DateInterval('P1W') yields d=7, and property_exists($i, 'w') is false. --- reference/datetime/dateinterval.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/datetime/dateinterval.xml b/reference/datetime/dateinterval.xml index 59d9eff0791c..e42ff185aef9 100644 --- a/reference/datetime/dateinterval.xml +++ b/reference/datetime/dateinterval.xml @@ -37,8 +37,8 @@ DateInterval::createFromDateString, or returned by DateTimeInterface::diff, it increments or decrements the individual component values. The date part, that is years, - months, weeks and days, always increments or decrements the individual - component values. The two therefore only give a different result when a + months and days, always increments or decrements the individual component + values. The two therefore only give a different result when a timezone transition falls within the time part of the interval; see Date/Time Arithmetic.