Mostrar fechas en español con PHP
¡Ama a las fechas por encima de todo, especialmente cuando estás desarrollando una aplicación!.
Durante años hemos tenido que pelearnos con las fechas. Ya sea trabajando con una base de datos o directamente desde el lenguaje de programación, tarde o temprano nos encontramos con el mismo problema: los formatos de fecha no siempre son los que queremos mostrar al usuario.
Y claro, no es lo mismo que nuestro cliente vea:
20th April 2018
que algo bastante más natural para nosotros:
20 de abril de 2018
Muchos CMS como WordPress nos facilitan enormemente esta tarea. Pero siempre puede aparecer un proyecto en el que tengamos que desarrollar nuestra propia aplicación sin utilizar ningún CMS.
Y aquí es donde tenemos que empezar a trabajar directamente con PHP.
El problema con las fechas en PHP
PHP dispone de muchas herramientas para trabajar con fechas, pero hay que distinguir entre generar una fecha, formatearla y traducir sus nombres al español.
Por ejemplo:
<?php
$fecha = new DateTime();
echo $fecha->format('d/m/Y');
Esto podría devolver:
20/08/2026
Perfecto.
Pero si queremos algo más descriptivo:
20 de agosto de 2026
necesitamos hacer algo más.
La solución moderna: IntlDateFormatter
En PHP moderno, una de las opciones más adecuadas para mostrar fechas localizadas es utilizar la extensión Intl, basada en ICU.
Esto nos permite indicar directamente que queremos trabajar con el idioma español.
Por ejemplo:
<?php
$fecha = new DateTime();
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::LONG,
IntlDateFormatter::NONE
);
echo $formateador->format($fecha);
El resultado será similar a:
20 de agosto de 2026
Mucho más sencillo y, sobre todo, más apropiado para aplicaciones actuales.
Mostrar una fecha con el formato que nosotros queramos
También podemos utilizar IntlDateFormatter con un patrón personalizado.
Por ejemplo:
<?php
$fecha = new DateTime();
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
'Europe/Madrid',
IntlDateFormatter::GREGORIAN,
"d 'de' MMMM 'de' yyyy"
);
echo $formateador->format($fecha);
Obtendremos:
20 de agosto de 2026
Podemos modificar el patrón para adaptarlo a las necesidades de nuestro proyecto.
¿Y si tenemos una fecha procedente de MySQL?
Esta situación es probablemente mucho más habitual en una aplicación real.
Imaginemos que nuestra base de datos almacena una fecha de esta manera:
2026-08-20 14:35:00
Podemos convertirla en un objeto DateTime y posteriormente utilizar nuestro formateador:
<?php
$fecha = new DateTime('2026-08-20 14:35:00');
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
'Europe/Madrid',
IntlDateFormatter::GREGORIAN,
"d 'de' MMMM 'de' yyyy"
);
echo $formateador->format($fecha);
Resultado:
20 de agosto de 2026
Y ya tenemos nuestra fecha almacenada en formato SQL convertida en una fecha legible para el usuario.
Mostrar también la hora
Si además queremos mostrar la hora, podemos utilizar un patrón diferente:
<?php
$fecha = new DateTime('2026-08-20 14:35:00');
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::LONG,
IntlDateFormatter::SHORT,
'Europe/Madrid'
);
echo $formateador->format($fecha);
El resultado será similar a:
20 de agosto de 2026, 14:35
De esta manera podemos localizar tanto la fecha como la hora.
¿Qué pasa con strftime()?
Aquí tenemos una diferencia importante respecto al artículo original.
Durante muchos años era habitual encontrar ejemplos como este:
<?php
setlocale(LC_TIME, 'es_ES.UTF-8');
echo strftime('%d de %B de %Y');
El problema es que strftime() fue declarado obsoleto en PHP 8.1 y no deberíamos utilizarlo en código nuevo.
Por tanto, aunque encontremos este método en multitud de tutoriales antiguos, actualmente es preferible utilizar IntlDateFormatter cuando necesitamos localización de fechas.
Importante si estás actualizando código antiguo
Si encuentras un proyecto antiguo que utiliza strftime(), no significa necesariamente que vaya a dejar de funcionar inmediatamente, pero conviene migrarlo si estás actualizando el proyecto a versiones modernas de PHP.
El problema de setlocale()
Otro detalle que suele provocar dolores de cabeza es setlocale().
En el código antiguo era habitual encontrarnos con:
setlocale(LC_TIME, 'es_ES.UTF-8');
o, en Windows:
setlocale(LC_TIME, 'spanish');
Esto dependía del sistema operativo y, además, de que el locale correspondiente estuviera instalado y disponible.
Por eso un código que funcionaba perfectamente en nuestro servidor Linux podía comportarse de manera diferente cuando lo ejecutábamos en Windows o en otro entorno.
Con IntlDateFormatter podemos especificar directamente:
'es_ES'
sin tener que depender de que el sistema tenga configurado exactamente el mismo locale.
Comprobar si tenemos instalada la extensión Intl
Para utilizar IntlDateFormatter, nuestra instalación de PHP necesita disponer de la extensión Intl.
Podemos comprobarlo rápidamente:
<?php
var_dump(class_exists('IntlDateFormatter'));
Si obtenemos:
bool(true)
la clase está disponible.
También podemos comprobar desde la consola:
php -m | grep intl
En Windows podemos utilizar:
php -m | findstr intl
Si no aparece, tendremos que habilitar o instalar la extensión intl dependiendo de nuestro entorno.
Un ejemplo completo
Vamos a juntar todo en un pequeño ejemplo que podríamos utilizar directamente en una aplicación:
<?php
date_default_timezone_set('Europe/Madrid');
$fecha = new DateTime('2026-08-20 14:35:00');
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
'Europe/Madrid',
IntlDateFormatter::GREGORIAN,
"d 'de' MMMM 'de' yyyy"
);
echo 'Hoy es: ' . $formateador->format($fecha);
Resultado:
Hoy es: 20 de agosto de 2026
Una alternativa sencilla: traducir el mes manualmente
Si estamos realizando algo extremadamente sencillo y no queremos utilizar Intl, también podemos formatear la fecha con DateTime y traducir los nombres de los meses nosotros mismos.
Por ejemplo:
<?php
$meses = [
1 => 'enero',
2 => 'febrero',
3 => 'marzo',
4 => 'abril',
5 => 'mayo',
6 => 'junio',
7 => 'julio',
8 => 'agosto',
9 => 'septiembre',
10 => 'octubre',
11 => 'noviembre',
12 => 'diciembre'
];
$fecha = new DateTime();
echo $fecha->format('d') . ' de '
. $meses[(int) $fecha->format('n')]
. ' de '
. $fecha->format('Y');
Esto produciría algo como:
20 de agosto de 2026
Es una solución perfectamente válida para casos sencillos, aunque para una aplicación que necesite trabajar con diferentes idiomas, formatos y localizaciones, Intl será una opción mucho más completa.
¿Y si necesitamos varios idiomas?
Aquí es donde IntlDateFormatter empieza a demostrar todo su potencial.
Podemos cambiar simplemente el locale:
$formateador = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::LONG,
IntlDateFormatter::NONE
);
Español:
'es_ES'
Inglés:
'en_US'
Francés:
'fr_FR'
Alemán:
'de_DE'
De esta manera podemos adaptar nuestra aplicación al idioma seleccionado por el usuario sin tener que crear manualmente todos los nombres de los meses y días.
¿Qué solución deberíamos utilizar hoy?
Si estamos trabajando con un proyecto antiguo y nos encontramos con:
setlocale(LC_TIME, ...); strftime(...);
conviene saber que estamos ante una solución de otra época.
Para código nuevo en PHP moderno, una opción recomendable es:
DateTime + IntlDateFormatter
De esta forma separamos claramente dos responsabilidades:
DateTime: trabajar con la fecha y la hora.IntlDateFormatter: presentar esa fecha según el idioma y la localización deseada.
Conclusión
Mostrar fechas en español desde PHP no tiene por qué convertirse en una pelea constante con los formatos, los locales y los sistemas operativos.
En código antiguo podemos encontrarnos con setlocale() y strftime(), pero para proyectos modernos es preferible utilizar las herramientas de internacionalización proporcionadas por PHP mediante la extensión Intl.
Con unas pocas líneas podemos transformar:
2026-08-20 14:35:00
en algo mucho más agradable para nuestro usuario:
20 de agosto de 2026, 14:35
Y si mañana nuestro cliente nos dice que quiere la aplicación en inglés, francés o alemán, tampoco tendremos que empezar a traducir los meses a mano.
Porque una cosa es programar una aplicación y otra muy distinta es obligar al usuario a leer:
20th August 2026
cuando podemos darle algo mucho más nuestro:
20 de agosto de 2026. 😉
Visitas: 1696
Automation & Data Specialist | Web Development | Data Processing & Integration
