@Dorothy

Как узнать timestamp полуночи после смены часового пояса?

Здравствуйте.
Использую Carbon являющийся расширением DateTime для работы с датой-временем.

Есть задача узнать время полуночи для заданной timestamp даты для заданных часовых поясов.
Например, есть timestamp = 1485943200 и нужно узнать timestamp полуночи для Москвы и Самары в этот день.
$initial = Carbon::createFromTimestamp(1485943200);
$moscow_midnight = $initial->copy()->timezone('Europe/Moscow')->modify('midnight')->getTimestamp();
$samara_midnight = $initial->copy()->timezone('Europe/Samara')->modify('midnight')->getTimestamp();

В результате получается
$moscow_midnight = 1485907200
$samara_midnight = 1485907200
что соответствует полуночи просто по 0 GMT, а не по указанным временным зонам.

Удается получить нужное время если только создавать объект Carbon'а сразу с указанием временной зоны и то, чего нужно получить.
$moscow_midnight = (new Carbon('midnight', 'Europe/Moscow'))->getTimestamp();
$samara_midnight = (new Carbon('midnight', 'Europe/Samara'))->getTimestamp();

Получается
$moscow_midnight = 1485982800
$samara_midnight = 1485979200

Что верно для текущего дня. Но такой метод не совсем то, что мне нужно. Так как вычислять полночь надо относительно заданного в $initial даты, да и вообще, если бы первый способ работал, то было бы удобнее, так как там просто меняю временную зону у конечных объектов и забираю что мне надо.
  • Вопрос задан
  • 692 просмотра
Решения вопроса 2
Lobotomist
@Lobotomist
Software Developer
Дело в том, что ->modify("midnight") не устанавливает время в начало суток. В документации такого модификатора нету. Для того, чтобы установить начало дня можно использовать ->startOfDay().

То есть ваш код принимает такой вид:
$initial = Carbon::createFromTimestamp(1485943200);
$moscow_midnight = $initial->copy()->timezone('Europe/Moscow')->startOfDay()->getTimestamp();
$samara_midnight = $initial->copy()->timezone('Europe/Samara')->startOfDay()->getTimestamp();


Еще нужно понимать, что в том коде что у вас под "этим днем" подразумевается день в часовом поясе UTC. Если вас интересует день в другом часовом поясе, нужно делать по-другому.

Я бы советовал заменить createFromTimestamp на createFromTimestampUtc - так поведение скрипта будет более прозрачно/очевидно. Хотя, фактически оно не изменится, но если, допустим, кто-то будет дебажить его может получиться "странная" ситуация. Если запустить код в phpio.net/tools/carbon

echo '<br />';require 'Carbon/Carbon.php';
use Carbon\Carbon;

$initial = Carbon::createFromTimestamp(0);
echo "{$initial} {$initial->tzName}<br />";
$samara = $initial->copy()->timezone('Europe/Samara')->startOfDay();
echo "{$samara} {$samara->tzName}<br />";

$initial = Carbon::createFromTimestampUtc(0);
echo "{$initial} {$initial->tzName}<br />";
$samara = $initial->copy()->timezone('Europe/Samara')->startOfDay();
echo "{$samara} {$samara->tzName}<br />";


его вывод будет таким:


1969-12-31 18:00:00 US/Central
1970-01-01 00:00:00 Europe/Samara
1970-01-01 00:00:00 +00:00
1970-01-01 00:00:00 Europe/Samara


И если бы выводилось только время, без часового пояса, оно могло бы смутить в первом случае, так как даты не совпадают.
Ответ написан
tkutru
@tkutru
A programming cat.
<?php
$tzMsk = new DateTimeZone('Europe/Moscow');
$tzSmr = new DateTimeZone('Europe/Samara');

$date1 = (new \DateTime())
->setTimestamp(1485943200)
->setTimezone($tzMsk);

$date2 = (new \DateTime())
->setTimestamp(1485943200)
->setTimezone($tzSmr);

var_dump([
    'date1' => $date1->format('Y-m-d H:i:s'),
    'date1mid' => $date1->setTime(0, 0, 0)->format('Y-m-d H:i:s'),
    'date1midtimestamp' => $date1->setTime(0, 0, 0)->getTimestamp(),
    'date2' => $date2->format('Y-m-d H:i:s'),
    'date2mid' => $date2->setTime(0, 0, 0)->format('Y-m-d H:i:s'),
    'date2midtimestamp' => $date2->setTime(0, 0, 0)->getTimestamp(),
]);
?>
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
wielski
@wielski
✔ Совет: Вам помогли? Отметьте ответы решением.
Попробуйте так:

$initial = Carbon::createFromTimestamp(1485943200);
$moscow_midnight = $initial->copy()->setTimezone('Europe/Moscow')->modify('midnight')->getTimestamp();
$samara_midnight = $initial->copy()->setTimezone('Europe/Samara')->modify('midnight')->getTimestamp();
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы