La hora que se guarda en la base de datos no es correcta - definir el timezone

Hoy me ha llegado una consulta sobre un problema relacionado con las fechas al usar Eloquent.

Resulta que la hora del servidor es la correcta pero al crear un registro se guarda con la hora incorrecta, concretamente con exactamente dos horas de error.

Esto me ha dado la pista de que debe ser un problema con la zona horaria. Efectivamente, he entrado en config/app.php y he buscado la clave 'timezone':

'timezone' => 'UTC',

La zona horaria UTC tiene un desfase de dos horas con respecto a la hora española. Así que basta con cambiar esta clave por:

'timezone' => 'Europe/Madrid',

Esto debería solucionar el problema.

Comprobando el problema

Antes de hacer el cambio del timezone primero he comprobado la existencia del problema usando Tinker.

Primero compruebo la hora del sistema con la función date de PHP:

>>> date("d-m-Y H:i");
=> "17-08-2016 12:00"

La hora del servidor, efectivamente, es correcta. Ahora vamos a ver qué pasa guando guardamos un registro en la base de datos. Voy a echar mano del modelo User (ojo, si es un servidor de producción no andes añadiendo datos basura):

>>> use App\User;
=> null
>>> $user = new User;
=> App\User {#692}

Añado un email falso para evitar que me salga un error al guardar (en el modelo User que viene por defecto con Laravel el campo email debe ser único).

>>> $user->email = 'email_inventado@email.com';

Y lo guardo:

>>> $user->save();
=> true

Por último compruebo el resultado:

>>> dd($user->toArray());
array:4 [
  "email" => "email_inventado@email.com"
  "updated_at" => "2016-08-17 10:01:35"
  "created_at" => "2016-08-17 10:01:35"
  "id" => 5
]

Ahí está, el reloj del sistema marca las 12:00 pero el registro se ha guardado con un error de dos horas, las 10:01.

Si ahora cambiamos el timezone a:

'timezone' => 'Europe/Madrid',

NOTA: Ahí debes poner el huso horario que te corresponda.

Ahora cierra Tinker y vuelve a entrar (de esta forma te evitas posibles problemas y se vuelve a cargar la configuración de nuevo).

Si ahora vuelves a crear un usuario verás que la hora ya es correcta:

>>> use App\User;
=> null
>>> $user = new User;
=> App\User {#683}
>>> $user->email = 'otro_email_inventado@email.com';
>>> $user->save();
=> true
>>> dd($user->toArray());
array:4 [
  "email" => "otro_email_inventado@email.com"
  "updated_at" => "2016-08-17 12:03:33"
  "created_at" => "2016-08-17 12:03:33"
  "id" => 6
]
Autor:
Nivel: Intermedio
Palabras clave:
Fecha publicado:
Fecha actualizado: 18-08-2016

Otros capítulos de la misma serie

Este capítulo es parte de la serie: Laravel pearls.

Y muchos más en preparación.

Disponible en los planes: Laravel hero