Spanish (Español) translation by Juan Pablo Diaz Cuartas (you can also view the original English article)
La extensión PHP Date / Time es un conjunto de clases que le permiten trabajar con casi todas las tareas relacionadas con la fecha y la hora. Ha estado disponible desde el lanzamiento de PHP 5.2 y la extensión introdujo varias clases nuevas, todas las cuales están mapeadas a escenarios de la vida real:
- Una fecha o una hora se representan mediante un objeto
DateTime
. - Una zona horaria del mundo está representada por un objeto
DateTimeZone
. - Los objetos
DateInterval
representan un intervalo. Por ejemplo, cuando decimos dos días a partir de ahora, los "dos días" son el intervalo. El objetoDateInterval
no se basa en una fecha u hora específica. - Los objetos
DatePeriod
representan un período entre dos fechas.
Ahora no dejes que los dos últimos te denuncien, vamos a ver el uso del mundo real de estos dos en un momento.
Desde date()
hasta DateTime
Cada vez que queremos mostrar una fecha, usamos date ()
, es simple y funciona. Solo necesita pasar el formato de fecha que necesita. Pero es un verdadero dolor manipular, un buen ejemplo es formatear fechas y horas de acuerdo con una zona horaria personalizada.
DateTime hace más que simplemente devolver una fecha formateada, pero antes de ir más allá, debe iniciar un nuevo objeto DateTime
que represente su fecha y hora. Entonces podemos hacer todo tipo de cosas interesantes con él. Se crea una nueva instancia al igual que cualquier otra clase de PHP.
1 |
$date = new DateTime(); |
El constructor de DateTime acepta un parámetro de cadena que por defecto es "ahora", la hora y fecha actuales. Para crear un objeto para una fecha específica, debe pasarle la fecha y hora específicas. El formateo del parámetro es autoexplicativo en la mayoría de los casos. A continuación puede encontrar algunos ejemplos diferentes de cómo construir su objeto DateTime
:
1 |
new DateTime('2013, March 24') //DateTime representing 2013, March 24 |
2 |
new DateTime('2013-03-24') //DateTime representing 2013, March 24 |
3 |
new DateTime('+2 days') //DateTime representing 2 days from now on. |
4 |
new DateTime('tomorrow') |
Cuando PHP tiene dificultades para entender el formato, lanzará una excepción. Se puede encontrar una lista completa del formato disponible en la documentación
Si no hay un formato que coincida con sus necesidades, puede especificar su propio formato utilizando DateTime :: createFromFormat
1 |
DateTime::createFromFormat('j-M-Y', '24-Mar-2013'); |
Ahora que tenemos un objeto DateTime en la mano, podemos hacer un montón de cosas, con bastante facilidad.
Marca de tiempo de Unix
1 |
$date->getTimestamp(); //returns a unix timestamp |
Modificación de fecha / hora
1 |
$date->setDate(2013, 12, 30); //yyyy, mm, dd will set the the specified date |
2 |
$date->setTime(12, 3, 20); //hh, mm, ss (optional) will modify the time |
3 |
$date->modify('tomorrow'); //string based manipulation |
4 |
$date->setTimestamp(1364798550); //modify using a unix timestamp |
Tenga en cuenta que cuando se establecen valores fuera de rango, PHP modificará la fecha en consecuencia. Por ejemplo, $date-> setDate (2013, 12, 35);
generará 2014-01-04
, lo mismo vale para el tiempo.
Trabajando con fechas múltiples
Ahora que estás obsesionado con DateTime, lo siguiente que sabes es que tus aplicaciones estarán llenas de objetos DateTime. Comenzarás a amar las fechas y los tiempos como nunca antes. De ahora en adelante, tendrás que lidiar con objetos DateTime, no con "strings" que debes pasar a la función strtotime
cuando necesites hacer un poco de matemática.
Digamos, por ejemplo, que necesitas comparar dos cumpleaños:
1 |
$sheldon = new DateTime('May 20th, 1980'); |
2 |
$neo = new DateTime('March 11th, 1962'); |
3 |
|
4 |
if ($sheldon > $neo) |
5 |
echo 'Sheldon is younger than neo'; |
Otro escenario podría estar comparando dos fechas. Podemos comparar fechas uno contra el otro como así:
1 |
$diff = $neo->diff($sheldon); |
La llamada diff
devuelve un objeto DateInterval. Si volcamos el valor de retorno:
1 |
DateInterval Object |
2 |
(
|
3 |
[y] => 18 |
4 |
[m] => 2 |
5 |
[d] => 9 |
6 |
[h] => 0 |
7 |
[i] => 0 |
8 |
[s] => 0 |
9 |
[invert] => 0 |
10 |
[days] => 6645 |
11 |
)
|
Estas son propiedades públicas. Puede generar algún resultado amigable desde un objeto DateInterval:
1 |
$diff->format('Neo is older by %Y years and %m months older'); //Neo is older by 18 years and 2 months |
Lo mejor del objeto DateInterval es que puede aplicar el intervalo a otro objeto DateTime:
1 |
$neo->add($diff); //neo's birthday changed to sheldon's |
Nota: las modificaciones de DateTime, como agregar, no devuelven nuevos objetos DateTime, sino que afectan al objeto original. Siempre ten esto en cuenta cuando pases objetos DateTime a través de tu aplicación. PHP 5.5 introdujo una nueva clase que devuelve nuevos objetos luego de la modificación.
diff
no es el único lugar donde puede generar un objeto DateInterval. Como es una clase, los objetos nuevos se pueden iniciar como de costumbre:
1 |
$new_diff = new DateInterval('P2Y'); |
La cantidad de años / meses / días, etc., se transfieren como una cadena al constructor. Se puede encontrar más información en la documentación del constructor.
Trabajando con Timezones
Al crear nuevos objetos DateTime, el segundo argumento del constructor define una zona horaria. Si omitimos esto, se tomará una zona horaria predeterminada de la date.timezone
de php.ini
. Puede modificar esto en tiempo de ejecución llamando a date_default_timezone_set
:
1 |
date_default_timezone_set('America/New_York'); |
2 |
new DateTime('today'); //datetime object is on New York time |
También puede cambiar las zonas horarias sobre la marcha. Como habrás adivinado, primero necesitamos un objeto Timezone.
1 |
$timezone = new DateTimeZone('America/New_York'); |
2 |
$sheldon->setTimezone($timezone); //sheldon's birthday now on to New York |
Puede definir la zona horaria al crear su nuevo objeto DateTime:
1 |
$sheldon = new DateTime('May 20th, 1980', $timezone); |
Sin embargo, una cosa importante a tener en cuenta es que setTimezone
modifica el objeto DateTime original. Lo que básicamente estamos preguntando es, "formatee esta fecha, a esta zona horaria" siempre que llamemos al método setTimezone
. Ahora, por otro lado, en el último ejemplo donde pasamos la zona horaria al constructor DateTime, estamos diciendo, "la fecha que estoy creando está en esta zona horaria".
Una lista de zonas horarias válidas está disponible en la documentación en línea.
DatePeriods
Creo que el manual oficial proporciona la mejor explicación:
Un período de fecha permite la iteración sobre un conjunto de fechas y horas, que se repiten a intervalos regulares, durante un período determinado.
DatePeriod nos permite generar un conjunto de DateTimes utilizando dos días que definimos entre un intervalo. Pasamos una fecha de inicio, un intervalo y una fecha de finalización. En cada intervalo, se crea un nuevo objeto DateTime.
Digamos que queremos obtener todas las fechas de nacimiento de Sheldon, desde su nacimiento:
1 |
//since birthdays occur every year, the interval is one year
|
2 |
$interval = new DateInterval('P1Y'); |
3 |
|
4 |
//third argument is the end date, new DateTime() == right now
|
5 |
$period = new DatePeriod($sheldon, $interval, new DateTime()); |
6 |
|
7 |
foreach($period as $dt) { |
8 |
//DateTime objects
|
9 |
echo $dt->format('Y-m-d - D'), "\n"; |
10 |
}
|
El resultado sería:
1 |
1981-05-20 - Wed |
2 |
1982-05-20 - Thu |
3 |
1983-05-20 - Fri |
4 |
1984-05-20 - Sun |
5 |
1985-05-20 - Mon |
6 |
1986-05-20 - Tue |
7 |
... |
Ahora, de forma predeterminada, DatePeriod
incluye la fecha de inicio que pasamos. Sin embargo, el cuarto argumento para el constructor nos permite omitir la fecha de inicio:
1 |
$period = new DatePeriod($sheldon, $interval, new DateTime(), DatePeriod::EXCLUDE_START_DATE); |
Veamos cuántas fiestas de cumpleaños ha tenido Neo antes de que naciera Sheldon:
1 |
$bdays = new DatePeriod($neo, $interval, $sheldon, DatePeriod::EXCLUDE_START_DATE); |
2 |
echo iterator_count($bdays); |
Extensión
Todas las clases que hemos cubierto hoy pueden ampliarse para usar con sus propios métodos. Un uso popular es extender DateTime con un método __toString
para que pueda imprimir correctamente un objeto DateTime sin tener que llamar al formato
.
Un par de escenarios de uso
-
Uno de mis enfoques personales para usar objetos DateTime es cuando trato con columnas de fecha / hora en bases de datos. Todas las fechas se almacenan como fechas de zona horaria UTC. El código de la aplicación solo funciona con los objetos DateTime, pero antes de que se genere la consulta final, todas las fechas tienen el formato UTC. Este enfoque me ha permitido trabajar con múltiples entradas de zona horaria fácilmente.
Puedo pasar un objeto de hora de Nueva York y olvidarme por completo de formatearlo, antes de ir a la base de datos. Puedo cambiar fácilmente entre las marcas de tiempo de Unix y el formato de fecha y hora en mi base de datos en cualquier momento, a mi código de aplicación no le importa siempre que reciba un objeto DateTime.
- También utilicé DateInterval para simplificar la lógica de pago de la suscripción. Usar los objetos de DateInterval para definir el tiempo entre la suscripción ha hecho las cosas realmente fáciles. Solo necesito aplicar el intervalo a la última fecha de pago.
¿Tiene algún buen ejemplo de uso de fecha / hora? Compártelos en los comentarios.
Envolver
La extensión de la fecha y hora tiene mucho que ofrecer, si está en la vanguardia, hay nuevas clases e interfaces introducidas desde PHP 5.5. Asegúrese de revisar el manual. Gracias por leer.