2008-12-06 18 views
20

Algunos problemas con las zonas horarias en PHP han estado en mi mente por un tiempo, y me preguntaba si hay mejores maneras de manejarlos que lo que estoy haciendo actualmente.Tratando con husos horarios en PHP

Todos los temas giran en torno a reformating base de datos almacenada fechas:

Cuando se trata de un sitio que tiene que soportar múltiples zonas horarias (para los usuarios), para normalizar la offest zona horaria de marcas de tiempo almacenados siempre almacenarlo con el servidor zona horaria utilizando el atributo CURRENT_TIMESTAMP o la función NOW().

De esta manera no tengo que considerar qué zona horaria se estableció para PHP cuando se ingresó la marca de tiempo (ya que las funciones de hora de PHP tienen en cuenta la zona horaria). Para cada usuario, de acuerdo con su preferencia puedo configurar la zona horaria en algún lugar de mi archivo de arranque usando:

date_default_timezone_set($timezone); 

cuando estoy buscando para formatear fechas con la función php date(), alguna forma de conversión tiene que tener lugar desde MySQL actualmente almacena la marca de tiempo en el formato Y-m-d H:i:s. Sin tener en cuenta la zona horaria, puede simplemente ejecutar:

$date = date($format,strtotime($dbTimestamp)); 

El problema con esto es que date() y strtotime() son ambas zonas horarias funciones conscientes, lo que significa que si la zona horaria PHP está configurado de manera diferente desde el servidor de zona horaria, la zona horaria compensado se aplicará dos veces (en lugar de una vez como quisiéramos).

Para resolver esto, suelo recuperar las marcas de tiempo de MySQL utilizando la función UNIX_TIMESTAMP() que no reconoce la zona horaria, lo que me permite aplicar date() directamente sobre ella, aplicando el desplazamiento de zona horaria solo una vez.

Realmente no me gusta este 'truco' porque ya no puedo recuperar esas columnas como lo haría normalmente, o uso * para buscar todas las columnas (a veces simplifica las consultas). Además, a veces simplemente no es una opción usar UNIX_TIMESTAMP() (especialmente cuando se usa con paquetes de código abierto sin mucha abstracción para la composición de consultas).

Otro problema es cuando se almacena la marca de tiempo, cuando el uso de CURRENT_TIMESTAMP o NOW() no es una opción: almacenar una marca de tiempo generada PHP la almacenará con el desplazamiento de la zona horaria que me gustaría evitar.

Probablemente me falta algo muy básico aquí, pero hasta ahora no he podido encontrar una solución genérica para manejar esos problemas, así que estoy obligado a tratarlos caso por caso. Sus pensamientos son bienvenidos

+1

Para cualquiera que encuentre esta pregunta y quiera leer sobre el tema: http://stackoverflow.com/questions/2532729/daylight-saving-time-and-timezone-best-practices – Industrial

Respuesta

1

Puede intentar forzar a MySQL a usar UTC en todas partes usando SET time_zone.

Lamentablemente no he recibido ninguna respuesta para el artículo de tiempo de viaje/UNIX_TIMESTAMP, de hecho, tengo el mismo problema con Postgres.

+0

Tal vez deberíamos apelar al SQL comité de normas para hacer cumplir el uso de una marca de tiempo numérico? ;) –

+0

Nah, estoy seguro de que las columnas de fecha y hora están ahí por una buena razón. Todavía no me he enterado ... – flussence

11

Hace unos meses, pasamos un tiempo pensando en esto. La técnica con la que terminamos es bastante simple:

  1. Almacena las fechas en GMT/UTC (por ejemplo, 0 timezone offset).
  2. Aplicar el desplazamiento actual de la zona horaria del usuario después de la recuperación desde la base de datos (por ejemplo, antes de mostrar al usuario o siempre que lo desee).

Utilizamos el formato de marcas de tiempo Unix. Pero eso no importa.

+1

De hecho, prefiero guardarlo en la zona horaria del servidor y dejar que las funciones conscientes de la zona horaria PHP se ocupen del cálculo del desplazamiento. Mi problema es que la marca de tiempo no se guarda en forma numérica, lo que PHP quiere para la función date() –

+0

Nosotros también usamos la misma solución después de algunas investigaciones. Me gustaría aquí las alternativas que las personas han usado. – Sean

6

A partir de PHP 5.2 se puede utilizar DateTime, que hace que trabajar con las zonas horarias fácil:

$datetime = new DateTime($dbTimestamp, $timezone); 
echo $datetime->format('Y-m-d H:i:s'); 
$datetime->setTimezone(new DateTimeZone('Pacific/Nauru')); 
echo $datetime->format('Y-m-d H:i:s'); 
0

no he encontrado ninguna solución elegante línea, así que he creado un script Timezone HTML select generator y aquí está la output directamente. Es algo como esto:

<select name="timezone" id="timezone"> 
    <optgroup label="UTC -11:00"> 
     <option value="Pacific/Midway">UTC -11:00 Midway</option> 
     <option value="Pacific/Niue">UTC -11:00 Niue</option> 
     <option value="Pacific/Pago_Pago">UTC -11:00 Pago_Pago</option> 
    </optgroup> 
    <optgroup label="UTC -10:00"> 
     <option value="America/Adak">UTC -10:00 Adak</option> 
     <option value="Pacific/Honolulu">UTC -10:00 Honolulu</option> 
     <option value="Pacific/Johnston">UTC -10:00 Johnston</option> 
     <option value="Pacific/Rarotonga">UTC -10:00 Rarotonga</option> 
     <option value="Pacific/Tahiti">UTC -10:00 Tahiti</option> 
    </optgroup> 
    . . . . . . . . . . . . . . 
    <optgroup label="UTC +13:00"> 
     <option value="Pacific/Apia">UTC +13:00 Apia</option> 
     <option value="Pacific/Enderbury">UTC +13:00 Enderbury</option> 
     <option value="Pacific/Fakaofo">UTC +13:00 Fakaofo</option> 
     <option value="Pacific/Tongatapu">UTC +13:00 Tongatapu</option> 
    </optgroup> 
    <optgroup label="UTC +14:00"> 
     <option value="Pacific/Kiritimati">UTC +14:00 Kiritimati</option> 
    </optgroup> 
</select> 

Enjoy!

Cuestiones relacionadas