Конвертация временных меток в локальное время с помощью date_l18n()
У меня есть cron-задача WordPress, которая периодически отправляет email и сохраняет временную метку отправки как опцию. Я хочу отобразить дату на странице настроек. Что-то вроде "Последнее письмо было отправлено 'x'". Я нахожусь на западном побережье США, поэтому наше время сейчас отличается на семь часов от UTC.
Ожидаемый результат от date_i18n() при передаче временной метки должен быть локально отформатированной датой с поправкой на семь часов от UTC. Однако функция возвращает время в UTC. Даже при попытке получить текущее время результат не соответствует ожидаемому.
Например: echo date_i18n('F d, Y H:i');
выводит April 05, 2013 11:36 как ожидалось, но echo date_i18n('F d, Y H:i',time());
выводит April 05, 2013 18:36.
Это задумано? Как я могу получить локально отформатированную дату из существующей временной метки? Спасибо за любую помощь.

Я знаю, что опаздываю на три месяца, но функция, которая вам здесь нужна, это get_date_from_gmt()
WordPress.
Функция принимает дату в формате GMT/UTC Y-m-d H:i:s
в качестве первого параметра и желаемый формат даты в качестве второго параметра. Она преобразует вашу дату в локальный часовой пояс, установленный на экране настроек.
Пример использования:
echo get_date_from_gmt( date( 'Y-m-d H:i:s', $my_unix_timestamp ), 'F j, Y H:i:s' );

Огромное спасибо, только что увидел это уведомление. Я изменил его на правильный ответ.

Я добавил конфигурацию даты и времени:
echo get_date_from_gmt ( date( 'Y-m-d H:i:s', $my_timestamp ), get_option('date_format') . ' - '. get_option('time_format') );

@NabilKadimi это отличное дополнение, но оно всё равно не переводит строку на правильный язык. Смотрите мой ответ для функции, которая учитывает все три настроенных параметра: язык, часовой пояс и формат даты.

Из кодекса:
current_time('timestamp') следует использовать вместо time(), чтобы получить локальное время блога. В WordPress PHP-функция time() всегда возвращает время в UTC и эквивалентна вызову current_time('timestamp', true).
Попробуйте так:
define( 'MY_TIMEZONE', (get_option( 'timezone_string' ) ? get_option( 'timezone_string' ) : date_default_timezone_get() ) );
date_default_timezone_set( MY_TIMEZONE );
echo date_i18n('F d, Y H:i', 1365194723);
Это устанавливает временную зону PHP по умолчанию на значение опции timezone_string в WordPress (если оно доступно) на время выполнения скрипта.

Правильно, но что если у меня произвольная временная метка? Например, пару дней назад, как мне получить скорректированное время вместо UTC?

Нет, даже попробовал на чистой установке WP с 2012, просто выполнив этот echo date_i18n('F d, Y H:i',1365194723)
код в начале index.php, он выдает UTC вместо времени Западного побережья США.

Вы правы, похоже, что date_i18n в основном предназначена для локального форматирования дат, а не для их корректировки. Я обновил свой ответ.

Да, я надеялся избежать необходимости вручную устанавливать часовой пояс, но если это единственный способ, что ж. Отмечено как отвеченное, спасибо за помощь.

WordPress вызывает date_default_timezone_set( 'UTC' );
, и кажется плохой идеей переопределять это, вызывая date_default_timezone_set
самостоятельно, так как код WordPress и плагины могут полагаться на это поведение.

date_i18n($format, $timestamp)
форматирует дату с учетом локали, но не учитывает часовой пояс. get_date_from_gmt($datestring, $format)
форматирует с учетом часового пояса, но не локали. Чтобы получить форматирование с учетом и часового пояса, и локали, я использую следующий код:
function local_date_i18n($format, $timestamp) {
$timezone_str = get_option('timezone_string') ?: 'UTC';
$timezone = new \DateTimeZone($timezone_str);
// Дата в локальном часовом поясе.
$date = new \DateTime(null, $timezone);
$date->setTimestamp($timestamp);
$date_str = $date->format('Y-m-d H:i:s');
// Предполагаем, что локальная дата - это UTC, чтобы получить timestamp,
// который передается в date_i18n().
$utc_timezone = new \DateTimeZone('UTC');
$utc_date = new \DateTime($date_str, $utc_timezone);
$timestamp = $utc_date->getTimestamp();
return date_i18n($format, $timestamp, true);
}
Пример программы:
$format = 'F d, Y H:i';
$timestamp = 1365186960;
$local = local_date_i18n($format, $timestamp);
$gmt = date_i18n($format, $timestamp);
echo "Местное: ", $local, " UTC: ", $gmt;
Вывод для часового пояса Лос-Анджелеса:
Местное: April 05, 2013 11:36 UTC: April 05, 2013 18:36
Ссылки:
- Документация
DateTimeZone
на php.net - Документация
DateTime
на php.net, включаяsetTimestamp
,getTimestamp
иformat
- Документация WordPress для
date_i18n

Конвертация UTC в строку с учетом часового пояса, языка и формата в настройках WordPress
Я создал хорошо документированную функцию, которая преобразует строку даты-времени в UTC в удобочитаемую строку с правильным языком, форматом и часовым поясом. Можете свободно использовать её.
Например, передав "2019-05-30 18:06:01"
(в UTC), функция вернет "30 мая 2019 г., 10:06 am"
.
/**
* Преобразует строку с датой и временем в UTC в удобочитаемую строку
* с учетом настроек языка, формата и часового пояса в WordPress.
*
* @param string $utc_date_and_time
* Пример: "2019-05-30 18:06:01"
* Аргумент должен быть в формате UTC.
* @return string
* Пример: "30 мая 2019 г., 10:06 am"
* Возвращает удобочитаемую строку даты-времени на правильном языке
* в соответствии с настройками администратора.
*/
function pretty_utc_date( string $utc_date ): string {
if (! preg_match( '/^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$/', $utc_date ) ) {
/* Другие форматы не тестировались, поэтому разрешен только этот. */
throw new InvalidArgumentException( "Ожидается аргумент в формате YYYY-MM-DD hh:mm:ss" );
}
$date_in_local_timezone = get_date_from_gmt( $utc_date );
/* Теперь $date_in_local_timezone содержит что-то вроде "2019-05-30 10:06:01"
* в часовом поясе из get_option( 'timezone_string' ), который настраивается
* в общих настройках WordPress в админке.
*/
/* К сожалению, мы не можем просто передать это в date_i18n WordPress, так как
* эта функция ожидает вторым аргументом количество секунд с 1/Jan/1970
* 00:00:00 в часовом поясе из get_option( 'timezone_string' ), что отличается
* от UNIX timestamp, который считает секунды с 1/Jan/1970 00:00:00 GMT. */
$seconds_since_local_1_jan_1970 =
(new DateTime( $date_in_local_timezone, new DateTimeZone( 'UTC' ) ))
->getTimestamp();
// Пример: 1559210761
/* Администраторы могут задать предпочтительный формат даты и времени
* в общих настройках WordPress в админке, нам нужно получить их. */
$settings_format = get_option( 'date_format' ) . ' '. get_option( 'time_format' );
// В этом примере $settings_format будет "F j, Y g:i a"
/* В этом примере WordPress установлен на итальянский,
* и конечный результат будет "30 maggio 2019 10:06 am" */
return date_i18n( $settings_format, $seconds_since_local_1_jan_1970 );
}
Ссылки:
- Документация WordPress по
get_date_from_gmt
- Документация PHP по
DateTimeZone
на php.net - Документация PHP по
DateTime
на php.net, включаяgetTimestamp
- Документация WordPress по
date_i18n
- Важно помнить, что WordPress выполняет
date_default_timezone_set( 'UTC' );
независимо от выбранного администратором часового пояса в интерфейсе, учитывайте это при работе со встроенными функциями PHP. См. документацию поdate_default_timezone_set
на php.net.

Метки времени (timestamp) не содержат информации о часовом поясе, поэтому почти никогда не требуется выполнять над ними математические операции.
Начиная с WordPress версии 5.3, самое простое решение для работы с конкретными метками времени — это функция wp_date()
:
$format = get_option( 'time_format' ) . ', ' . get_option( 'date_format' );
echo wp_date( $format, $your_timestamp );
Для получения текущих даты и времени используйте соответствующую функцию current_datetime
:
echo current_datetime()->format( $format );

Метки времени (timestamp) представляют собой количество секунд, прошедших с 1 января 1970 года 00:00 UTC в некоторых определениях, или количество секунд с 1 января 1970 года в локальном часовом поясе в других определениях.

@Flimm В PHP (и, следовательно, в WordPress) метки времени всегда указываются по времени GMT. См. time()
.

Добавьте смещение часового пояса к вашей временной метке.
$offset = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
return date_i18n( get_option( 'date_format' ), $ts + $offset );
Или лучше:
$tz = new DateTimeZone( get_option( 'timezone_string' ) );
$offset_for_that_time = timezone_offset_get ( $tz , new DateTime("@{$ts}") );
return date_i18n ( get_option( 'date_format' ), $ts + $offset_for_that_time );

Этот вариант работает на моей машине (ничего другое не сработало):
$tz = new DateTimeZone(get_option('timezone_string'));
$dtz = new DateTimeZone('GMT');
foreach($posts as $key => $post){
$gmt_date = DateTime::createFromFormat('Y-m-d H:i:s', $post->PostDateGMT, $dtz);
$gmt_date->setTimeZone($tz);
$posts[$key]->PostDateGMT = $gmt_date->format('Y-m-d H:i:s');
}
Оригинальный код: https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/
Здесь не используется date_l18n()
, но, думаю, можно применить её позже...

get_the_time
принимает аргумент $post
примерно с 2008 года.
