If you have ever pushed a post live only to see it labeled “57 years ago” on the public site while your dashboard calmly insists it went up ten minutes past the hour, you know the particular sting of this bug. It does not break the layout. It does not trigger a fatal error. It simply ages your content by half a century, and staring at your theme files will not make the number budge.
This issue tends to survive the usual checks. You grep through single.php, archive.php, and functions.php searching for a mangled get_the_date() call. Everything looks standard. You reload the live page. The ghost of 1968 still haunts your byline. At that point, the problem has almost nothing to do with your templates and everything to do with how time passes through the WordPress stack.
Why That Specific Number Keeps Appearing
The figure “57 years ago” is not random. WordPress themes often display relative time through the human_time_diff() function, which compares a post’s timestamp against the current moment and prints a friendly phrase like “2 hours ago.” For that math to work, PHP needs a valid Unix timestamp—a count of seconds since January 1, 1970, the Unix epoch.
When something strips or corrupts the timestamp before it reaches that calculation, the function frequently ends up comparing zero (or a similarly invalid starting point) against now. The result is a span stretching back roughly five and a half decades, creeping forward one calendar year at a time. It is a symptom of a missing or misread time value, not a database full of retro blog posts.
The Dashboard Deception
One of the more frustrating aspects of this bug is the split personality of your admin panel. Inside wp-admin, the Posts list shows the correct publication date because WordPress often pulls that directly from the MySQL wp_posts table and formats it server-side without running it through the relative-time filter. The frontend, however, may rely on a theme or plugin that calls human_time_diff(), or it may pass the raw database value through a chain of PHP timezone conversions that the backend bypasses entirely.
So the data is usually still intact. It is the pipeline between the database and the rendered HTML that develops a kink.
PHP Version and Timezone Settings
Start with PHP. Hosting panels make version swaps look harmless, but PHP handles time objects differently across major releases. A site running legacy PHP 7.4 code on a sudden PHP 8.1 environment can encounter subtle shifts in how DateTime objects initialize empty or malformed strings. If your php.ini file leaves date.timezone undefined, PHP defaults to UTC and assumes the server knows best. WordPress may disagree.
Check whether anyone has hardcoded a timezone declaration inside wp-config.php. A line like date_default_timezone_set( 'Asia/Kolkata' ); feels helpful, but WordPress expects to manage its own clock through the value set under Settings > General. Forcing a PHP-level offset can create a race condition where core believes the time is local and PHP believes it is universal. When those offsets collide during a timestamp conversion, the result returned to your template can collapse to zero.
Server Time Zone Configurations
Your MySQL server carries its own idea of local time. WordPress writes two dates for every post: post_date in the site’s local time, and post_date_gmt in Universal Time. If the database global time_zone flips—say, from SYSTEM to +00:00 after a migration—PHP’s strtotime() can fail to reconcile the stored string with what it expects. The database still stores 2024-03-15 14:30:00, but the context around it shifts, and the parsed output becomes false or null in PHP.
Real-world example: a managed host moves your database from a node running MySQL 5.7 with SYSTEM time to a cluster running MariaDB 10.11 set to strict UTC. Your theme never changes. Your WordPress settings never change. Yet get_the_time( 'U' )—the Unix timestamp format—suddenly returns an empty value for some posts, and the relative-time function falls back to that epoch-zero calculation. The fix is aligning the application timezone, database timezone, and operating system clock so that WordPress does not have to guess which frame of reference to use.
Database Timestamp Formats
Le cœur de WordPress stocke les dates d'article dans des colonnes MySQL DATETIME, et non dans des champs TIMESTAMP. Cette distinction est importante car DATETIME conserve une valeur calendaire sans prise en compte du fuseau horaire dans les anciennes versions de MySQL, tandis que TIMESTAMP convertit tout en UTC en arrière-plan. Si un plugin ou un outil de migration a modifié le schéma de votre table wp_posts, ou si une ancienne sauvegarde a restauré des dates "zéro" invalides dans la table, WordPress peut lire une valeur telle que 0000-00-00 00:00:00 et la transmettre discrètement à votre thème.
Les modes MySQL modernes, en particulier NO_ZERO_DATE et STRICT_TRANS_TABLES, rejettent ces marqueurs de position zéro. Si un script de sauvegarde les a insérés lors d'une migration, la base de données a pu les tronquer ou les transformer en valeurs nulles lors de l'importation. Vous pouvez vérifier cela rapidement avec une requête SQL directe :
SELECT ID, post_title, post_date, post_date_gmt
FROM wp_posts
WHERE post_status = 'publish'
ORDER BY post_date DESC
LIMIT 10;
Si les colonnes brutes semblent correctes mais que le site affiche toujours des dates historiques lointaines, la corruption se produit après la requête. Si les colonnes elles-mêmes contiennent des zéros, vous avez trouvé la fuite dans la tuyauterie.
Conflits de plugins avec les fonctions de date
Les plugins qui filtrent l'affichage des dates sont des coupables fréquents. Les outils multilingues tels que WPML ou Polylang s'accrochent à get_the_date pour traduire les noms des mois. Les plugins de mise en cache interceptent le HTML final. L'une ou l'autre de ces couches peut accidentellement transmettre une chaîne non formatée à une fonction qui attend un entier Unix.
Un plugin de traduction peut remplacer « March 15, 2024 » par son équivalent localisé, mais si un thème transmet ensuite cette chaîne localisée à strtotime() à l'intérieur d'une fonction personnalisée, l'analyseur échoue sur les caractères non anglais et renvoie false. Cette valeur false arrive dans human_time_diff(), qui compare zéro à l'heure actuelle, produisant ainsi le fameux écart d'un demi-siècle.
Les couches de cache d'objets compliquent encore davantage la situation. Redis ou Memcached peuvent stocker un objet WP_Post sérialisé provenant d'une requête qui a brièvement échoué à analyser la date. Chaque visiteur suivant reçoit cet objet corrompu directement depuis la RAM, contournant entièrement la base de données. Le problème persiste sur le site en production car votre environnement de production dispose d'une infrastructure de cache qui fait défaut à votre installation locale.
Une liste de contrôle pratique pour le débogage
Comme le symptôme se cache profondément dans la pile, vous devez retirer les couches systématiquement jusqu'à ce que les dates redeviennent correctes.
- Interrogez directement la base de données. Ouvrez phpMyAdmin ou utilisez WP-CLI et inspectez les valeurs brutes de
post_date. Si elles sont correctes, la base de données n'est pas le problème. - Passez à un thème par défaut. Activez Twenty Twenty-Four ou Twenty Twenty-Three. Si le bug disparaît, auditez votre thème actif et votre thème enfant pour trouver des fonctions personnalisées qui enveloppent l'affichage de l'heure.
- Désactivez les plugins. Renommez temporairement le dossier
/wp-content/pluginsou désactivez tous les plugins depuis le tableau de bord. Réactivez-les un par un, en vérifiant le front-end après chaque activation. - Lisez le journal d'erreurs. Recherchez des avertissements de fuseau horaire, des erreurs
DateTimeou des plaintes liées àstrtotime(). Ils pointent souvent vers l'exact
