В Laravel для работы со временем используется удобное расширение Carbon. Тут мы столкнулись с его не очевидным поведением при применении timestamp. Unix timestamp всегда в часовом поясе UTC, поэтому логично предположить, что если передаю в Carbon timestamp он будет работать с часовым поясом UTC. Например:
$timestamp = 1595552400; // 2020-07-24T01:00:00+00:00 $carbon = Carbon::createFromTimestamp($timestamp); echo $carbon->format(Carbon::ATOM); // 2020-07-24T01:00:00+00:00
Еще в Carbon есть замечательная функция startOfDay, которая возвращает начало дня. В нашем примере она ожидаемо работает так:
$start_of_day_timestamp = $carbon->startOfDay()->timestamp; $carbon = Carbon::createFromTimestamp($start_of_day_timestamp); echo $start_of_day_timestamp; //1595548800 echo $carbon->format(Carbon::ATOM); //2020-07-24T00:00:00+00:00
Дальше мы можем работать с другими часовыми поясами, например, так:
echo $carbon->timezone('America/New_York')->startOfDay()->timestamp; // 1595476800 echo $carbon->timezone('America/New_York')->format(Carbon::ATOM); // 2020-07-23T20:00:00-04:00
Обратите внимание что startOfDay возвращает разный timestamp для разных часовых поясов: 1595548800 != 1595476800
. Это тоже ожидаемо, начало дня в разных часовых поясах отличается относительно Гринвича.
Каково же было наше удивление, когда мы получили такое:
$timestamp = 1595552400; // 2020-07-24T01:00:00+00:00 $carbon = Carbon::createFromTimestamp($timestamp); echo $carbon->startOfDay()->timestamp; // 1595476800 echo $carbon->format(Carbon::ATOM); ; // 2020-07-23T20:00:00-04:00
Т.е. мы нигде явно не прописывали часовой пояс, мы передаем timestamp, поэтому ожидаем что работаем в UTC, а на выходе получаем начало дня в NYC. В результате в тестах мы смогли повторить ошибку, выглядит это так:
$timestamp = 1595552400; // 2020-07-24T01:00:00+00:00 date_default_timezone_set('UTC'); $carbon = Carbon::createFromTimestamp($timestamp); echo $carbon->startOfDay()->format(Carbon::ATOM); // 2020-07-24T00:00:00+00:00 date_default_timezone_set('America/New_York'); $carbon = Carbon::createFromTimestamp($timestamp); echo $carbon->startOfDay()->format(Carbon::ATOM); // 2020-07-23T00:00:00-04:00
Это означает что при использовании timestamp Carbon использует часовой пояс по умолчанию, а не UTC. Фикс выглядит так:
date_default_timezone_set('UTC'); $carbon = Carbon::createFromTimestamp($timestamp, 'UTC'); echo $carbon->startOfDay()->format(Carbon::ATOM); // 2020-07-24T00:00:00+00:00 date_default_timezone_set('America/New_York'); $carbon = Carbon::createFromTimestamp($timestamp, 'UTC'); echo $carbon->startOfDay()->format(Carbon::ATOM); // 2020-07-24T00:00:00+00:00
Keep calm and use UTC timezone.