0

PHP DateTime and DateTimeZone works incorrectly for me around DST change dates.

I wrote a simple function to convert local time to UTC and I called it with the midnight time from the 24th of Oct to the 2nd of Nov with the timezones Europe/Paris and CET:

<?php
function timeToUTC($time, $timeZone, $format='Y-m-d H:i:sP')
{
    $dt = new DateTime($time, new DateTimeZone($timeZone));
    $dt->setTimeZone(new DateTimeZone('UTC'));
    return $dt->format($format);
}

$localTimes = [
    '2020-10-24 00:00:00',
    '2020-10-25 00:00:00',
    '2020-10-26 00:00:00',
    '2020-10-27 00:00:00',
    '2020-10-28 00:00:00',
    '2020-10-29 00:00:00',
    '2020-10-30 00:00:00',
    '2020-10-31 00:00:00',
    '2020-11-01 00:00:00',
    '2020-11-02 00:00:00',
];

foreach (['Europe/Paris', 'CET'] as $timeZone) {
    echo "******** $timeZone ********" . PHP_EOL;
    foreach ($localTimes as $localTime) {
        $utcTime = timeToUTC($localTime, $timeZone);
        echo "$localTime $utcTime" . PHP_EOL;
    }
}

The output:

******** Europe/Paris ********
2020-10-24 00:00:00 2020-10-23 22:00:00+00:00
2020-10-25 00:00:00 2020-10-24 22:00:00+00:00
2020-10-26 00:00:00 2020-10-25 23:00:00+00:00
2020-10-27 00:00:00 2020-10-26 23:00:00+00:00
2020-10-28 00:00:00 2020-10-27 23:00:00+00:00
2020-10-29 00:00:00 2020-10-28 23:00:00+00:00
2020-10-30 00:00:00 2020-10-29 23:00:00+00:00
2020-10-31 00:00:00 2020-10-30 23:00:00+00:00
2020-11-01 00:00:00 2020-10-31 23:00:00+00:00
2020-11-02 00:00:00 2020-11-01 23:00:00+00:00
******** CET ********
2020-10-24 00:00:00 2020-10-23 23:00:00+00:00
2020-10-25 00:00:00 2020-10-24 23:00:00+00:00
2020-10-26 00:00:00 2020-10-25 23:00:00+00:00
2020-10-27 00:00:00 2020-10-26 23:00:00+00:00
2020-10-28 00:00:00 2020-10-27 23:00:00+00:00
2020-10-29 00:00:00 2020-10-28 23:00:00+00:00
2020-10-30 00:00:00 2020-10-29 23:00:00+00:00
2020-10-31 00:00:00 2020-10-30 23:00:00+00:00
2020-11-01 00:00:00 2020-10-31 23:00:00+00:00
2020-11-02 00:00:00 2020-11-01 23:00:00+00:00

For Europe/Paris I got the changed DST instead of the 31st of October at the 26th. And even worth that there is no change at all for the timezone CET.

What do I wrong? Is it about a PHP bug?

It's about PHP on Ubuntu. I tried Ubuntu 16.04 with PHP 7.2.34-8 and Ubuntu 18.04 with 7.2.24-0.

Tibor Nagy
  • 1,185
  • 1
  • 15
  • 28
  • Can you explain why you think this is wrong? Checked both, this is 100% what I would expect the output to be. – Evert Nov 19 '20 at 17:34
  • I see two problems: 1: DST was changed at the 31st of October this year. So up to the 31st October I should get the previous day 22:00:00, after that 23:00:00. 2. CET and Europe/Paris are simple 2 names of the same timezone, they should give the same result. – Tibor Nagy Nov 19 '20 at 17:54
  • No.The changeover from summer to winter time was on October 25th in 2020 and not 31th! – jspit Nov 19 '20 at 17:57
  • 1
    What jspit said, and also this is not true about CET. Countries that are in the CET timezone and have DST rules switch to CEST 6 months out of the year. There are some african countries that have CET all year long though. – Evert Nov 19 '20 at 18:00
  • Yes, @Evert, Europe/Paris and CET are not the same timezone. – jspit Nov 19 '20 at 18:28
  • Sorry, but you're right. The changeover from summer to winter time was in the night from the 31st October to 1st of November in the [USA] but not in Europe.(https://www.timeanddate.com/time/change/usa), [Europe](https://www.timeanddate.com/time/change/france/paris) – Tibor Nagy Nov 19 '20 at 18:28

1 Answers1

3

The output is correct.

France switched to winter time October 25th, and most abbreviation timezones like CET don't have DST rules.

Countries like France are in CET 6 months out of the year, and CEST the other 6. The abbreviated timezones are confusing, so generally I just recommend people to not use them.

echo (new DateTime('2020-10-01', new DateTimeZone('Europe/Paris')))->format('T'), "\n";
echo (new DateTime('2020-11-01', new DateTimeZone('Europe/Paris')))->format('T'), "\n";

Output:

CEST
CET
Evert
  • 93,428
  • 18
  • 118
  • 189