C# : Dates et temps
DateTime, DateOnly, TimeOnly, TimeSpan, DateTimeOffset : quel type pour quel besoin, et les pièges à éviter (fuseaux, parsing, immuabilité).
C# : Dates et temps
Le .NET propose plusieurs types pour manipuler dates et temps, et choisir le bon évite la majorité des bugs : décalages de fuseau, dates ambiguës, comparaisons fausses. Cette page est la vue d'ensemble ; chaque type a ensuite sa page détaillée.
Point commun à tous : ce sont des types valeur (struct), donc immuables. Une opération comme AddDays ne modifie rien, elle retourne une nouvelle valeur.
# La famille
| Type | Rôle |
|---|---|
DateTime | une date et une heure (avec un Kind : local, UTC ou non spécifié) |
DateOnly | une date seule, sans heure ni fuseau (.NET 6+) |
TimeOnly | une heure d'horloge seule, sans date (.NET 6+) |
TimeSpan | une durée ou un écart entre deux instants |
DateTimeOffset | un instant précis, avec son décalage par rapport à UTC |
TimeZoneInfo | les fuseaux horaires et les conversions entre eux |
# Quel type pour quel besoin
Pars toujours de ce que la donnée représente vraiment :
| Besoin | Type conseillé |
|---|---|
| Un instant unique dans le temps (log, horodatage, création d'un enregistrement) | DateTimeOffset (ou DateTime en UTC) |
| Une date sans heure (anniversaire, date de facture, échéance) | DateOnly |
| Une heure sans date (ouverture d'un magasin, alarme) | TimeOnly |
| Une durée, un délai, un écart | TimeSpan |
| Une date + heure locale simple, sans enjeu de fuseau | DateTime |
| Convertir un instant d'un fuseau à un autre | TimeZoneInfo |
La règle courte : stocke en UTC, affiche en local. Ne garde une heure locale nue (DateTime.Now) que pour un affichage immédiat, jamais pour persister un instant.
# Les pièges communs
Now vs UtcNow
DateTime local = DateTime.Now; // heure de la machine, dépend du fuseau et de l'heure d'été
DateTime utc = DateTime.UtcNow; // heure universelle, stable partoutDateTime local = DateTime.Now; // heure de la machine, dépend du fuseau et de l'heure d'étéDateTime utc = DateTime.UtcNow; // heure universelle, stable partoutPersister un DateTime.Now pose problème : au changement d'heure ou sur un autre serveur, l'instant devient ambigu. Pour un horodatage, prends UtcNow ou mieux, un DateTimeOffset.
Ce sont des valeurs immuables
DateTime d = new DateTime(2026, 1, 1);
d.AddDays(10); // INUTILE : le résultat est jeté
d = d.AddDays(10); // BIEN : on réaffecte la nouvelle valeurDateTime d = new DateTime(2026, 1, 1);d.AddDays(10); // INUTILE : le résultat est jetéd = d.AddDays(10); // BIEN : on réaffecte la nouvelle valeurLe parsing dépend de la culture
// "01/02/2026" : 1er février ou 2 janvier ? Ça dépend de la culture !
DateTime ambigu = DateTime.Parse("01/02/2026");
// BIEN : format explicite et culture invariante
DateTime clair = DateTime.ParseExact("2026-02-01", "yyyy-MM-dd", CultureInfo.InvariantCulture);// "01/02/2026" : 1er février ou 2 janvier ? Ça dépend de la culture !DateTime ambigu = DateTime.Parse("01/02/2026"); // BIEN : format explicite et culture invarianteDateTime clair = DateTime.ParseExact("2026-02-01", "yyyy-MM-dd", CultureInfo.InvariantCulture);Le mauvais type pour la donnée
Une date de naissance n'a ni heure ni fuseau : un DateTime t'expose à des bugs de minuit et de décalage. Utilise DateOnly. Un délai de 90 minutes n'est pas une date : c'est un TimeSpan.
# Par où continuer
- DateTime en profondeur - construction, propriétés, arithmétique,
Kind, formatage et parsing - DateOnly et TimeOnly - les types dédiés date seule et heure seule (.NET 6+)
- TimeSpan - les durées, et le piège
Total...vs composantes - DateTimeOffset et fuseaux horaires - l'instant sans ambiguïté et les conversions de fuseau
Ces types sont des struct : relis la mémoire pour comprendre pourquoi une copie est indépendante de l'originale.
Pour aller plus loin
C# : DateTime en profondeur
Construire, lire, calculer, formater et parser un DateTime, et bien gérer le Kind (local, UTC, non spécifié).
C# : DateOnly et TimeOnly
Les types dédiés à une date seule ou une heure seule (.NET 6+) : pourquoi ils existent, et comment les manipuler.
C# : TimeSpan
Représenter une durée ou un écart : construction, le piège composantes vs totaux, opérations et formatage.
C# : DateTimeOffset et fuseaux horaires
L'instant sans ambiguïté (date + heure + offset UTC), la comparaison par instant, et les conversions de fuseau avec TimeZoneInfo.