Convirtiendo marcas de tiempo a hora local con date_l18n()
Tengo un trabajo cron de WordPress que envía un correo electrónico periódicamente y guarda la marca de tiempo cuando fue enviado como una opción, y me gustaría mostrar una fecha en una página de configuración. Algo como "El último correo electrónico fue enviado el 'x'". Estoy en la costa oeste de EE.UU., por lo que nuestra hora está actualmente siete horas desfasada de UTC.
La salida esperada de date_i18n(), pasándole la marca de tiempo, sería una fecha formateada localmente con un ajuste de siete horas desde UTC. Sin embargo, devuelve la hora en UTC. Incluso al intentar obtener la hora actual no devuelve lo que yo pensaría que sería la salida esperada.
Por ejemplo: echo date_i18n('F d, Y H:i');
muestra April 05, 2013 11:36 como se esperaba, pero echo date_i18n('F d, Y H:i',time());
muestra April 05, 2013 18:36.
¿Es esto intencional? ¿Cómo puedo devolver una fecha formateada localmente desde una marca de tiempo preexistente? Gracias por cualquier ayuda.

Sé que llego tres meses tarde, pero la función que buscas aquí es get_date_from_gmt()
de WordPress.
La función acepta una fecha GMT/UTC en formato Y-m-d H:i:s
como primer parámetro y el formato de fecha deseado como segundo parámetro. Convertirá tu fecha a la zona horaria local configurada en la pantalla de Ajustes.
Ejemplo de uso:
echo get_date_from_gmt( date( 'Y-m-d H:i:s', $my_unix_timestamp ), 'F j, Y H:i:s' );

Mil gracias, acabo de ver esta notificación emergente. Lo cambié a la respuesta correcta.

Agregué la configuración de fecha y hora:
echo get_date_from_gmt ( date( 'Y-m-d H:i:s', $my_timestamp ), get_option('date_format') . ' - '. get_option('time_format') );

@NabilKadimi ese es un gran añadido, pero aún no traduce el string al idioma correcto. Mira mi respuesta para ver una función que tiene en cuenta los tres elementos configurados: idioma, zona horaria y formato de fecha.

Del codex:
current_time('timestamp') debería usarse en lugar de time() para devolver la hora local del blog. En WordPress, PHP time() siempre devolverá UTC y es lo mismo que llamar a current_time('timestamp', true).
Prueba esto:
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);
Esto establece la fecha predeterminada de PHP a la opción timezone_string de WP, si está disponible, durante la ejecución del script.

Correcto, pero ¿qué pasa si tengo una marca de tiempo arbitraria? Digamos de hace un par de días, ¿cómo obtengo la hora ajustada en lugar de la hora UTC?

No, incluso lo probé en una instalación limpia de WP con 2012 ejecutando esta declaración echo date_i18n('F d, Y H:i',1365194723)
al principio de index.php, eso me da UTC en lugar de la hora de la Costa Oeste de EE.UU.

Tienes razón, parece que date_i18n es principalmente para el formateo local de fechas, en lugar del ajuste de fechas. He actualizado mi respuesta.

Sí, esperaba evitar tener que configurar la zona horaria manualmente, pero si esa es la única manera, así será. Marcado como respondido, gracias por la ayuda.

WordPress llama a date_default_timezone_set( 'UTC' );
, parece una mala idea anular esto llamando a date_default_timezone_set
tú mismo, ya que el código de WordPress y los plugins podrían depender de ese comportamiento.

date_i18n($format, $timestamp)
formatea según el idioma local, pero no según la zona horaria. get_date_from_gmt($datestring, $format)
formatea según la zona horaria, pero no según el idioma local. Para obtener un formato que respete tanto la zona horaria como el idioma local, estoy haciendo lo siguiente:
function local_date_i18n($format, $timestamp) {
$timezone_str = get_option('timezone_string') ?: 'UTC';
$timezone = new \DateTimeZone($timezone_str);
// La fecha en la zona horaria local.
$date = new \DateTime(null, $timezone);
$date->setTimestamp($timestamp);
$date_str = $date->format('Y-m-d H:i:s');
// Suponer que la fecha local es UTC para obtener el timestamp
// que pasaremos a 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);
}
Ejemplo de programa:
$format = 'F d, Y H:i';
$timestamp = 1365186960;
$local = local_date_i18n($format, $timestamp);
$gmt = date_i18n($format, $timestamp);
echo "Local: ", $local, " UTC: ", $gmt;
Salida para la zona horaria de Los Ángeles:
Local: Abril 05, 2013 11:36 UTC: Abril 05, 2013 18:36
Referencias:
- Documentación de
DateTimeZone
en php.net - Documentación de
DateTime
en php.net, incluyendosetTimestamp
,getTimestamp
yformat
- Documentación de WordPress sobre
date_i18n

Convertir UTC a cadena en zona horaria, idioma y formato según las opciones de WordPress
He creado una función bien documentada que convierte una cadena de fecha y hora en UTC a una cadena de fecha y hora legible en el idioma, formato y zona horaria correctos. Siéntete libre de copiarla.
Por ejemplo, al pasar "2019-05-30 18:06:01"
(en UTC) devolvería "Mayo 30, 2019 10:06 am"
.
/**
* Dada una cadena con la fecha y hora en UTC, devuelve una cadena legible en el
* idioma, formato y zona horaria configurados en las opciones de WordPress.
*
* @param string $utc_date_and_time
* ej: "2019-05-30 18:06:01"
* Este argumento debe estar en UTC.
* @return string
* ej: "Mayo 30, 2019 10:06 am"
* Devuelve una cadena de fecha y hora legible en el idioma correcto y
* siguiendo la configuración del administrador.
*/
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 ) ) {
/* No he probado otros formatos, así que solo permito este. */
throw new InvalidArgumentException( "Se esperaba que el argumento esté en formato YYYY-MM-DD hh:mm:ss" );
}
$date_in_local_timezone = get_date_from_gmt( $utc_date );
/* $date_in_local_timezone ahora es algo como "2019-05-30 10:06:01"
* en la zona horaria de get_option( 'timezone_string' ), configurada en
* los ajustes generales de WordPress en la interfaz de usuario del backend.
*/
/* Desafortunadamente, no podemos simplemente pasar esto a date_i18n de WordPress, ya que
* espera que el segundo argumento sea el número de segundos desde 1/Ene/1970
* 00:00:00 en la zona horaria de get_option( 'timezone_string' ), que no es lo mismo
* que un timestamp UNIX, que es el número de segundos desde
* 1/Ene/1970 00:00:00 GMT. */
$seconds_since_local_1_jan_1970 =
(new DateTime( $date_in_local_timezone, new DateTimeZone( 'UTC' ) ))
->getTimestamp();
// ej: 1559210761
/* Los administradores pueden configurar un formato de fecha y un formato de hora
* preferidos en los ajustes generales de WordPress en la interfaz de usuario del backend,
* necesitamos obtener eso. */
$settings_format = get_option( 'date_format' ) . ' '. get_option( 'time_format' );
// $settings_format en este ejemplo es "F j, Y g:i a"
/* En este ejemplo, la instalación de WordPress está configurada en italiano,
* y el resultado final es "Mayo 30, 2019 10:06 am" */
return date_i18n( $settings_format, $seconds_since_local_1_jan_1970 );
}
Referencias:
- Documentación de
get_date_from_gmt
en WordPress - Documentación de
DateTimeZone
en php.net - Documentación de
DateTime
en php.net, incluyendogetTimestamp
- Documentación de
date_i18n
en WordPress - Vale la pena recordar que WordPress ejecuta
date_default_timezone_set( 'UTC' );
independientemente de la zona horaria que el administrador haya seleccionado en la interfaz de usuario, así que tenlo en cuenta al determinar el comportamiento de las funciones integradas de PHP. Ver documentación dedate_default_timezone_set
en php.net.

Las marcas de tiempo (timestamps) no tienen zona horaria, por lo que casi nunca necesitas operar matemáticamente con ellas.
Desde WordPress 5.3, la solución más sencilla para marcas de tiempo específicas es wp_date()
:
$format = get_option( 'time_format' ) . ', ' . get_option( 'date_format' );
echo wp_date( $format, $your_timestamp );
Para la fecha y hora actual, usa la función apropiadamente llamada current_datetime
:
echo current_datetime()->format( $format );

Los timestamps son el número de segundos desde el 1 de enero de 1970 00:00 UTC para algunas definiciones de timestamp, o el número de segundos desde el 1 de enero de 1970 en la zona horaria local para otras definiciones de timestamp.

@Flimm En PHP (y por lo tanto en WordPress), los timestamps siempre están en GMT. Ver time()
.

Añade el desplazamiento de zona horaria a tu marca de tiempo.
$offset = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
return date_i18n( get_option( 'date_format' ), $ts + $offset );
o mejor aún:
$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 );

Esto es lo que parece funcionar en mi máquina (ninguna de las otras soluciones funcionó):
$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');
}
Código original: https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/
No está usando date_l18n()
pero supongo que se podría usar más adelante...

get_the_time
ha aceptado un argumento $post
desde aproximadamente 2008.
