Formats de dates SQL : Oracle, MySQL et PostgreSQL comparés
Vous avez déjà écrit une requête SQL qui fonctionnait parfaitement sur une base de données, puis échouait sur une autre à cause d’une simple histoire de date ? C’est l’un des pièges les plus courants du développement : chaque système de gestion de base de données (SGBD) a sa propre façon de convertir, formater et comparer les dates. Une requête Oracle ne se transpose pas telle quelle sur MySQL, ni sur PostgreSQL.
Cet article compare la gestion des dates sur les trois SGBD les plus répandus — Oracle, MySQL/MariaDB et PostgreSQL — pour convertir, formater et comparer des dates. Et pour finir, quelques conseils pour écrire du SQL aussi portable que possible.
Pourquoi les dates posent problème
Une date, en base de données, est stockée dans un format interne (un nombre, généralement) qui n’a rien à voir avec la façon dont on l’affiche. Le problème surgit à deux moments : quand on veut afficher une date dans un format lisible (transformer la valeur interne en texte « 15/03/2026 »), et quand on veut interpréter une chaîne de texte comme une date (transformer « 15/03/2026 » en vraie valeur date).
Chaque SGBD a ses propres fonctions pour ces deux opérations, et surtout ses propres codes de format. C’est là que naissent la plupart des incompatibilités. Un même besoin — « afficher une date au format année-mois-jour » — s’écrit de trois façons différentes selon la base.
Formater une date (date → texte)
C’est l’opération la plus fréquente : prendre une date stockée et l’afficher dans un format choisi. Voici comment afficher une date au format ISO YYYY-MM-DD sur chaque système.
Oracle utilise la fonction TO_CHAR :
SELECT TO_CHAR(date_commande, 'YYYY-MM-DD') FROM commandes;
PostgreSQL utilise aussi to_char, avec les mêmes codes de format qu’Oracle (c’est une bonne nouvelle pour la portabilité entre ces deux-là) :
SELECT to_char(date_commande, 'YYYY-MM-DD') FROM commandes;
MySQL/MariaDB, en revanche, utilise une fonction au nom différent, DATE_FORMAT, et surtout des codes de format complètement différents, avec des % :
SELECT DATE_FORMAT(date_commande, '%Y-%m-%d') FROM commandes;
Les trois requêtes produisent le même résultat (« 2026-03-15 »), mais aucune n’est interchangeable avec les autres. C’est le cœur du problème.
Les codes de format : le vrai piège
La difficulté ne vient pas tant du nom des fonctions que des codes de format. Oracle et PostgreSQL utilisent des codes littéraux (YYYY, MM, DD), tandis que MySQL/MariaDB utilise des codes préfixés par %. Voici la correspondance des plus courants :
| Élément | Oracle / PostgreSQL | MySQL / MariaDB |
|---|---|---|
| Année (4 chiffres) | YYYY |
%Y |
| Mois (2 chiffres) | MM |
%m |
| Jour (2 chiffres) | DD |
%d |
| Heure (24h) | HH24 |
%H |
| Minutes | MI |
%i |
| Secondes | SS |
%s |
Un piège classique se cache dans ce tableau : en MySQL, les minutes s’écrivent %i, et non %m — car %m désigne le mois ! Confondre les deux donne des résultats absurdes sans lever d’erreur. C’est une source de bugs redoutable, car la requête s’exécute sans broncher.
Ainsi, pour afficher un horodatage complet « 2026-03-15 14:30:00 », on écrira 'YYYY-MM-DD HH24:MI:SS' sur Oracle et PostgreSQL, mais '%Y-%m-%d %H:%i:%s' sur MySQL.
Interpréter une date (texte → date)
L’opération inverse — transformer une chaîne de texte en vraie valeur date — est tout aussi importante, notamment pour insérer des données ou filtrer. Là encore, les fonctions diffèrent.
Oracle utilise TO_DATE :
SELECT TO_DATE('15/03/2026', 'DD/MM/YYYY') FROM dual;
(Notez le FROM dual, obligatoire dans Oracle pour une requête sans table réelle.)
PostgreSQL utilise to_date avec les mêmes codes :
SELECT to_date('15/03/2026', 'DD/MM/YYYY');
MySQL/MariaDB utilise STR_TO_DATE, avec les codes % :
SELECT STR_TO_DATE('15/03/2026', '%d/%m/%Y');
On retrouve la même logique : même principe, trois écritures différentes. À noter qu’en cas de format incorrect, MySQL renvoie NULL avec un avertissement plutôt qu’une erreur bloquante — un comportement à connaître pour ne pas laisser passer des conversions ratées silencieusement.
Un piège de migration à connaître. Quand on vient d’Oracle, on est tenté de chercher un TO_DATE équivalent côté MySQL/MariaDB. Attention : sur MySQL, TO_DATE n’existe pas — il faut utiliser STR_TO_DATE. Côté MariaDB, une fonction TO_DATE de style Oracle a bien été ajoutée, mais seulement à partir de la version 12.3 (2026). Sur toute version antérieure — c’est-à-dire l’immense majorité des installations en production, qui tournent en 10.x ou 11.x — elle n’est pas disponible, et STR_TO_DATE reste la seule option. En revanche, STR_TO_DATE lui-même est universel : il existe depuis très longtemps sur les deux systèmes, sans souci de version. Dernier détail : même là où TO_DATE existe (MariaDB 12.3+), il attend des masques de style Oracle (YYYY-MM-DD), et non les codes % de STR_TO_DATE — les deux fonctions ne se pilotent donc pas de la même façon.
Comparer et filtrer sur des dates
Un point crucial pour les performances : quand on filtre sur une date dans une clause WHERE, il faut éviter d’appliquer une fonction de conversion sur la colonne elle-même. Écrire quelque chose comme WHERE TO_CHAR(date_commande, 'YYYY-MM-DD') = '2026-03-15' force la base à convertir chaque ligne avant de comparer, ce qui empêche l’utilisation d’un index et ralentit énormément la requête sur une grosse table.
La bonne pratique est de convertir la valeur de comparaison, pas la colonne :
-- Oracle : bon réflexe
SELECT * FROM commandes
WHERE date_commande = TO_DATE('2026-03-15', 'YYYY-MM-DD');
Ainsi, la colonne date_commande reste « intacte » et son index peut être utilisé. Ce principe vaut sur tous les SGBD : ne transformez jamais la colonne indexée dans le WHERE si vous pouvez transformer l’autre côté de la comparaison à la place.
Écrire du SQL portable
Si vous devez écrire des requêtes destinées à tourner sur plusieurs SGBD (par exemple lors d’une migration, ou pour un logiciel qui supporte plusieurs bases), voici quelques principes pour limiter la casse.
Adoptez le format ISO 8601 (YYYY-MM-DD) partout. C’est le format le plus universellement compris. La plupart des SGBD acceptent une chaîne ISO directement dans une comparaison, sans conversion explicite, car c’est un format non ambigu. Il a aussi l’avantage de se trier correctement en ordre alphabétique (contrairement au format européen ou américain).
Privilégiez CAST quand c’est possible. La fonction CAST fait partie du standard SQL (ANSI) et fonctionne sur tous les grands SGBD. Pour une conversion simple, CAST('2026-03-15' AS DATE) est souvent plus portable que les fonctions propriétaires. Réservez TO_CHAR, DATE_FORMAT et consorts aux formatages avancés qui l’exigent vraiment.
Isolez le code spécifique. Quand une partie de votre SQL doit forcément utiliser une fonction propriétaire (formatage complexe, par exemple), regroupez ces morceaux à un endroit identifiable plutôt que de les disséminer partout. Le jour où vous changez de base, vous saurez exactement quoi adapter.
Normalisez à l’entrée. Convertissez les dates dans un format standard dès qu’elles entrent dans le système, plutôt que de jongler avec des formats hétérogènes tout au long du traitement. Une donnée propre en entrée évite mille conversions en aval.
Le cas des fuseaux horaires
Un mot sur un sujet connexe mais épineux : les fuseaux horaires. Dès qu’une application couvre plusieurs régions, stocker les dates sans information de fuseau devient risqué — « 08:00 à Paris » n’est pas le même instant que « 08:00 à New York ». La recommandation générale est de stocker les horodatages en UTC (temps universel) et de ne les convertir en heure locale qu’au moment de l’affichage. Les types TIMESTAMP WITH TIME ZONE (Oracle, PostgreSQL) aident à gérer proprement ces cas, mais c’est un sujet à part entière qui mérite sa propre étude.
En résumé
La gestion des dates entre SGBD se résume à quelques constats :
- Oracle et PostgreSQL partagent les fonctions
TO_CHAR/to_charetTO_DATE/to_dateavec les mêmes codes de format (YYYY-MM-DD). - MySQL/MariaDB utilise
DATE_FORMATetSTR_TO_DATEavec des codes préfixés par%— attention au piège%ipour les minutes. - Dans un
WHERE, convertissez la valeur de comparaison, pas la colonne, pour préserver les index. - Pour du code portable : ISO 8601 partout, CAST quand possible, et isolez le code spécifique.
Les dates resteront toujours un point de vigilance en SQL, mais une fois ces réflexes acquis, on évite l’immense majorité des mauvaises surprises. Le meilleur conseil tient en une phrase : standardisez tôt, et ne laissez jamais une conversion de date implicite décider à votre place.