Si alguna vez has publicado una entrada solo para verla etiquetada como "hace 57 años" en el sitio público, mientras tu panel de control insiste tranquilamente en que se subió hace diez minutos, conoces el dolor particular de este error. No rompe el diseño. No provoca un error fatal. Simplemente envejece tu contenido medio siglo, y quedarse mirando los archivos de tu tema no hará que el número cambie.

Este problema suele sobrevivir a las comprobaciones habituales. Buscas con grep en single.php, archive.php y functions.php tratando de encontrar una llamada a get_the_date() malformada. Todo parece estándar. Recargas la página en vivo. El fantasma de 1968 sigue acechando tu firma. En ese punto, el problema casi no tiene nada que ver con tus plantillas y tiene todo que ver con cómo el tiempo fluye a través de la pila (stack) de WordPress.

Por qué sigue apareciendo ese número específico

La cifra "hace 57 años" no es aleatoria. Los temas de WordPress suelen mostrar el tiempo relativo a través de la función human_time_diff(), que compara la marca de tiempo (timestamp) de una entrada con el momento actual e imprime una frase amigable como "hace 2 horas". Para que ese cálculo funcione, PHP necesita un timestamp de Unix válido: un recuento de segundos desde el 1 de enero de 1970, la época Unix.

Cuando algo elimina o corrompe el timestamp antes de que llegue a ese cálculo, la función suele terminar comparando cero (o un punto de partida similarmente inválido) con el momento actual. El resultado es un lapso que se remonta aproximadamente a cinco décadas y media, avanzando un año natural a la vez. Es un síntoma de un valor de tiempo ausente o mal leído, no de una base de datos llena de entradas de blog retro.

El engaño del panel de control

Uno de los aspectos más frustrantes de este error es la personalidad dividida de tu panel de administración. Dentro de wp-admin, la lista de Entradas muestra la fecha de publicación correcta porque WordPress suele extraerla directamente de la tabla MySQL wp_posts y la formatea en el servidor sin pasarla por el filtro de tiempo relativo. El frontend, sin embargo, puede depender de un tema o plugin que llame a human_time_diff(), o puede pasar el valor bruto de la base de datos a través de una cadena de conversiones de zona horaria de PHP que el backend omite por completo.

Por lo tanto, los datos suelen estar intactos. Es la canalización entre la base de datos y el HTML renderizado la que presenta un problema.

Versión de PHP y configuración de la zona horaria

Empecemos con PHP. Los paneles de hosting hacen que los cambios de versión parezcan inofensivos, pero PHP maneja los objetos de tiempo de manera diferente entre las versiones principales. Un sitio que ejecute código heredado de PHP 7.4 en un entorno repentino de PHP 8.1 puede encontrar cambios sutiles en cómo los objetos DateTime inicializan cadenas vacías o malformadas. Si tu archivo php.ini deja date.timezone sin definir, PHP utiliza UTC por defecto y asume que el servidor sabe qué es lo mejor. WordPress podría no estar de acuerdo.

Comprueba si alguien ha dejado escrita de forma fija una declaración de zona horaria dentro de wp-config.php. Una línea como date_default_timezone_set( 'Asia/Kolkata' ); parece útil, pero WordPress espera gestionar su propio reloj a través del valor establecido en Ajustes > General. Forzar un desfase a nivel de PHP puede crear una condición de carrera (race condition) donde el núcleo cree que la hora es local y PHP cree que es universal. Cuando esos desfases colisionan durante una conversión de timestamp, el resultado devuelto a tu plantilla puede colapsar a cero.

Configuraciones de la zona horaria del servidor

Tu servidor MySQL tiene su propia idea de la hora local. WordPress escribe dos fechas para cada entrada: post_date en la hora local del sitio, y post_date_gmt en tiempo universal. Si la time_zone global de la base de datos cambia —por ejemplo, de SYSTEM a +00:00 tras una migración—, la función strtotime() de PHP puede fallar al intentar reconciliar la cadena almacenada con lo que espera. La base de datos sigue almacenando 2024-03-15 14:30:00, pero el contexto a su alrededor cambia, y el resultado analizado se convierte en false o null en PHP.

Ejemplo del mundo real: un hosting gestionado mueve tu base de datos de un nodo que ejecuta MySQL 5.7 con hora SYSTEM a un clúster que ejecuta MariaDB 10.11 configurado en UTC estricto. Tu tema nunca cambia. Tus ajustes de WordPress nunca cambian. Sin embargo, get_the_time( 'U' ) —el formato de timestamp de Unix— de repente devuelve un valor vacío para algunas entradas, y la función de tiempo relativo recurre a ese cálculo de época cero. La solución es alinear la zona horaria de la aplicación, la zona horaria de la base de datos y el reloj del sistema operativo para que WordPress no tenga que adivinar qué marco de referencia utilizar.

Formatos de timestamp de la base de datos

WordPress core stores post dates in MySQL DATETIME columns, not TIMESTAMP fields. That distinction matters because DATETIME holds a calendar value without_zone awareness in older MySQL versions, whereas TIMESTAMP converts everything to UTC behind the scenes. If a plugin or migration tool has altered your wp_posts schema, or if an old backup restored invalid zero dates into the table, WordPress may read a value like 0000-00-00 00:00:00 and quietly hand it off to your theme.

Modern MySQL modes, particularly NO_ZERO_DATE and STRICT_TRANS_TABLES, reject those zero placeholders. If a backup script inserted them during a migration, the database might have truncated or nulled them on import. You can verify this quickly with a direct SQL query:

SELECT ID, post_title, post_date, post_date_gmt 
FROM wp_posts 
WHERE post_status = 'publish' 
ORDER BY post_date DESC 
LIMIT 10;

If the raw columns look correct but the site still displays ancient history, the corruption is happening after the query. If the columns themselves contain zeroes, you have found the leak in the plumbing.

Plugin Conflicts with Date Functions

Plugins that filter date output are common culprits. Multilingual tools such as WPML or Polylang hook into get_the_date to translate month names. Caching plugins intercept the final HTML. Either layer can accidentally pass an unformatted string into a function expecting a Unix integer.

A translation plugin might replace “March 15, 2024” with its localized equivalent, but if a theme then pipes that localized string into strtotime() inside a custom function, the parser fails on non-English characters and returns false. That false value hits human_time_diff(), which compares zero against now, producing the infamous half-century gap.

Object cache layers complicate this further. Redis or Memcached can store a serialized WP_Post object from a request that briefly failed to parse the date. Every subsequent visitor receives that corrupted object straight from RAM, bypassing the database entirely. The issue persists on the live site because your production stack has cache infrastructure that your local install lacks.

A Practical Debugging Checklist

Because the symptom hides deep in the stack, you need to peel layers systematically until the dates snap back into place.

  1. Query the database directly. Open phpMyAdmin or run WP-CLI and inspect the raw post_date values. If they are correct, the database is not the problem.
  2. Switch to a default theme. Activate Twenty Twenty-Four or Twenty Twenty-Three. If the bug disappears, audit your active theme and child theme for custom functions wrapping time output.
  3. Silence the plugins. Rename the /wp-content/plugins folder temporarily, or disable all plugins from the dashboard. Re-enable them one by one, checking the frontend after each activation.
  4. Read the error log. Look for timezone warnings, DateTime errors, or strtotime() complaints. They often point to the exact