PHP: вычитание 1 часа из времени экономии Dailight через один час после переключения - PullRequest
2 голосов
/ 25 мая 2020

Я наткнулся на странную вещь в PHP. Находясь в часовом поясе Europe/Oslo, я вычитал один час из метки времени 2020-03-29 03:00:00 (это именно то время, когда происходит сдвиг времени Dailight Savings Time), и это привело к точно такой же метке времени 2020-03-29 03:00:00! Это должно было привести к 2020-03-29 01:00:00. Почему это не так?

Вплоть до 2020-03-29 03:59:59 он возвращает точно такую ​​же метку времени при вычитании одного часа (пробовал и sub(), и modify()). В следующую секунду после этого он правильно дает 2020-03-29 03:00:00.

Вы можете воспроизвести это следующим образом:

date_default_timezone_set('Europe/Oslo');
echo (new \DateTime('2020-03-29 03:00:00'))->sub(new \DateInterval('PT1H'))->format('Y-m-d H:i:s');

Я тестировал это в PHP 7.1.33, 7.3. 10 и 7.3.18.

PS. Однако добавление 1 часа к 2020-03-29 01:00:00 дает 2020-03-29 03:00:00.

1 Ответ

1 голос
/ 26 мая 2020

Хотя я согласен с тем, что это плохое / ошибочное поведение, вы можете избежать этого, строго всегда сохраняя или вычисляя даты только в UT C. Считайте, что часовые пояса предназначены только для отображения, и вы избежите головной боли много .

например:

// input
$utc     = new DateTimeZone('UTC');
$user_tz = new DateTimeZone('Europe/Oslo');
$input   = new DateTime('2020-03-29 03:00:00', $user_tz);
$storage = (clone $input)->setTimezone($utc);
var_dump(
    $input->format('c'),
    $storage->format('c')
);

// compute
$interval = new DateInterval('PT1H');
$storage->sub($interval);
var_dump(
    $storage->format('c')
);

// display
$display = (clone $storage)->setTimezone($user_tz);
var_dump(
    $display->format('c')
);

Вывод:

string(25) "2020-03-29T03:00:00+02:00"
string(25) "2020-03-29T01:00:00+00:00"
string(25) "2020-03-29T00:00:00+00:00"
string(25) "2020-03-29T01:00:00+01:00"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...