"Same" DateInterval instances lead to different results, depending on the origin (in combination with DST-switches)
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- C
- Estrellas
- 40.4k
- Forks
- 8.2k
- Merge medio
- 2 d 13 h
- PR fusionados (30 d)
- 96
Descripción
Description
The following code:
<?php
function getIntervalSpecificationFromDateInterval(DateInterval $interval): string
{
$specification = '';
if ($interval->invert) {
$specification .= '-';
}
$specification .= 'P';
$specification .= $interval->y ? $interval->y . 'Y' : '';
$specification .= $interval->m ? $interval->m . 'M' : '';
$specification .= $interval->d ? $interval->d . 'D' : '';
if ($interval->h + $interval->i + $interval->s) {
$specification .= 'T';
$specification .= $interval->h ? $interval->h . 'H' : '';
$specification .= $interval->i ? $interval->i . 'M' : '';
$specification .= $interval->s ? $interval->s . 'S' : '';
}
if ($specification === 'P' || $specification === '-P') {
$specification = 'PT0S';
}
return $specification;
}
$timezone = new DateTimeZone('Europe/Berlin');
$dstSwitchA = new DateTimeImmutable('2025-03-30 01:00:00', $timezone);
$dstSwitchB = new DateTimeImmutable('2025-10-26 01:00:00', $timezone);
$durationA = new DateInterval('PT3H');
$durationB = (new DateTimeImmutable('2025-03-28 01:00:00', $timezone))->diff(
new DateTimeImmutable('2025-03-28 04:00:00', $timezone),
true
);
$durationC = (new DateTimeImmutable('2025-03-28 01:00:00', $timezone))->diff(
new DateTimeImmutable('2025-03-28 04:00:00', $timezone),
);
$durationD = (new DateTimeImmutable('2025-03-28 01:00:00', $timezone))->diff(
new DateTimeImmutable('2025-03-28 04:00:00', $timezone),
);
$durationD = new DateInterval(getIntervalSpecificationFromDateInterval($durationD));
// Test 1st DST-switch (+1 hour)
echo 'TEST 1 (DST-switch +1 hour)' . PHP_EOL;
$datetimeA = $dstSwitchA->setTimezone($timezone)->add($durationA);
echo 'Constructed: ' . $datetimeA->format('Y-m-d H:i:s') . PHP_EOL; // expected: 2025-03-30 05:00:00
$datetimeB = $dstSwitchA->setTimezone($timezone)->add($durationB);
echo 'Diff (absolute): ' . $datetimeB->format('Y-m-d H:i:s') . PHP_EOL; // expected: 2025-03-30 05:00:00
$datetimeC = $dstSwitchA->setTimezone($timezone)->add($durationC);
echo 'Diff (relative): ' . $datetimeC->format('Y-m-d H:i:s') . PHP_EOL; // expected: 2025-03-30 05:00:00
$datetimeD = $dstSwitchA->setTimezone($timezone)->add($durationD);
echo 'Workaround: ' . $datetimeD->format('Y-m-d H:i:s') . PHP_EOL; // expected: 2025-03-30 05:00:00
echo PHP_EOL;
echo 'TEST 2 (DST-switch -1 hour)' . PHP_EOL;
// Test 2nd DST-switch (-1 hour)
// Expected value: 2025-10-26 03:00:00
$datetimeA = $dstSwitchB->setTimezone($timezone)->add($durationA);
echo 'Constructed: ' . $datetimeA->format('Y-m-d H:i:s') . PHP_EOL;
$datetimeB = $dstSwitchB->setTimezone($timezone)->add($durationB);
echo 'Diff (absolute): ' . $datetimeB->format('Y-m-d H:i:s') . PHP_EOL;
$datetimeC = $dstSwitchB->setTimezone($timezone)->add($durationC);
echo 'Diff (relative): ' . $datetimeC->format('Y-m-d H:i:s') . PHP_EOL;
$datetimeD = $dstSwitchB->setTimezone($timezone)->add($durationD);
echo 'Workaround: ' . $datetimeD->format('Y-m-d H:i:s') . PHP_EOL;
Resulted in this output:
TEST 1 (DST-switch +1 hour)
Constructed: 2025-03-30 05:00:00
Diff (absolute): 2025-03-30 04:00:00
Diff (relative): 2025-03-30 04:00:00
Workaround: 2025-03-30 05:00:00
TEST 2 (DST-switch -1 hour)
Constructed: 2025-10-26 03:00:00
Diff (absolute): 2025-10-26 04:00:00
Diff (relative): 2025-10-26 04:00:00
Workaround: 2025-10-26 03:00:00
But I expected this output instead:
TEST 1 (DST-switch +1 hour)
Constructed: 2025-03-30 05:00:00
Diff (absolute): 2025-03-30 05:00:00
Diff (relative): 2025-03-30 05:00:00
Workaround: 2025-03-30 05:00:00
TEST 2 (DST-switch -1 hour)
Constructed: 2025-10-26 03:00:00
Diff (absolute): 2025-10-26 03:00:00
Diff (relative): 2025-10-26 03:00:00
Workaround: 2025-10-26 03:00:00
PHP Version
PHP 8.3.16 (cli) (built: Jan 14 2025 20:07:09) (NTS Visual C++ 2019 x64)
Copyright (c) The PHP Group
Zend Engine v4.3.16, Copyright (c) Zend Technologies
with Zend OPcache v8.3.16, Copyright (c), by Zend Technologies
with Xdebug v3.4.1, Copyright (c) 2002-2025, by Derick Rethans
Tested with PHP 8.1.0 to 8.4.8
Operating System
No response
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Comienza ejecutando la reproducción de PHP proporcionada contra el comportamiento de DateTimeImmutable::add() y DateInterval descrito en el issue, comparando los intervalos creados por el constructor y por DateTimeImmutable::diff(). Rastrea la implementación de fecha/hora de PHP responsable de las transiciones de DST; se considera terminado cuando intervalos equivalentes de tres horas produzcan las marcas de tiempo esperadas en ambos casos de cambio de DST, con cobertura de regresión para los escenarios demostrados.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- php
- Área
- backend
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 35/100