C# : DateTime en profondeur
Construire, lire, calculer, formater et parser un DateTime, et bien gérer le Kind (local, UTC, non spécifié).
C# : DateTime en profondeur
DateTime représente une date et une heure. C'est le type historique du .NET pour le temps : puissant, mais avec des pièges autour des fuseaux. Voici tout ce qu'il permet.
# Construire un DateTime
DateTime maintenant = DateTime.Now; // date + heure locale de la machine
DateTime utc = DateTime.UtcNow; // date + heure universelle
DateTime aujourdhui = DateTime.Today; // aujourd'hui à 00:00:00 (heure locale)
DateTime date = new DateTime(2026, 9, 1); // 1er septembre 2026, 00:00
DateTime precise = new DateTime(2026, 9, 1, 14, 30, 0); // ...à 14:30:00DateTime maintenant = DateTime.Now; // date + heure locale de la machineDateTime utc = DateTime.UtcNow; // date + heure universelleDateTime aujourdhui = DateTime.Today; // aujourd'hui à 00:00:00 (heure locale) DateTime date = new DateTime(2026, 9, 1); // 1er septembre 2026, 00:00DateTime precise = new DateTime(2026, 9, 1, 14, 30, 0); // ...à 14:30:00Now et UtcNow sont des propriétés : chaque lecture renvoie l'instant courant. Ne les appelle qu'une fois si tu veux une valeur stable dans un calcul.
# Lire ses composantes
DateTime d = new DateTime(2026, 9, 1, 14, 30, 15);
int annee = d.Year; // 2026
int mois = d.Month; // 9
int jour = d.Day; // 1
int heure = d.Hour; // 14
DayOfWeek jourSemaine = d.DayOfWeek; // DayOfWeek.Tuesday (un enum)
int jourAnnee = d.DayOfYear; // 244
TimeSpan heureDuJour = d.TimeOfDay; // 14:30:15 en tant que durée depuis minuit
DateTime minuit = d.Date; // même jour à 00:00:00DateTime d = new DateTime(2026, 9, 1, 14, 30, 15); int annee = d.Year; // 2026int mois = d.Month; // 9int jour = d.Day; // 1int heure = d.Hour; // 14DayOfWeek jourSemaine = d.DayOfWeek; // DayOfWeek.Tuesday (un enum)int jourAnnee = d.DayOfYear; // 244 TimeSpan heureDuJour = d.TimeOfDay; // 14:30:15 en tant que durée depuis minuitDateTime minuit = d.Date; // même jour à 00:00:00DayOfWeek est un enum ; TimeOfDay renvoie un TimeSpan, et Date remet l'heure à minuit.
# Faire des calculs
Les méthodes Add... retournent une nouvelle valeur (le type est immuable) :
DateTime d = new DateTime(2026, 9, 1);
DateTime demain = d.AddDays(1);
DateTime moisProchain = d.AddMonths(1);
DateTime dansUneHeure = d.AddHours(1);
DateTime hier = d.AddDays(-1); // les valeurs négatives reculentDateTime d = new DateTime(2026, 9, 1); DateTime demain = d.AddDays(1);DateTime moisProchain = d.AddMonths(1);DateTime dansUneHeure = d.AddHours(1);DateTime hier = d.AddDays(-1); // les valeurs négatives reculentSoustraire deux DateTime donne un écart (TimeSpan) ; ajouter un TimeSpan donne un DateTime :
DateTime debut = new DateTime(2026, 9, 1, 9, 0, 0);
DateTime fin = new DateTime(2026, 9, 1, 17, 30, 0);
TimeSpan duree = fin - debut; // 08:30:00
DateTime plusTard = debut + TimeSpan.FromHours(2); // 11:00:00DateTime debut = new DateTime(2026, 9, 1, 9, 0, 0);DateTime fin = new DateTime(2026, 9, 1, 17, 30, 0); TimeSpan duree = fin - debut; // 08:30:00DateTime plusTard = debut + TimeSpan.FromHours(2); // 11:00:00La comparaison marche avec les opérateurs habituels :
if (fin > debut) { /* ... */ }
int ordre = debut.CompareTo(fin); // -1 : debut est avant finif (fin > debut) { /* ... */ }int ordre = debut.CompareTo(fin); // -1 : debut est avant fin# Le Kind : local, UTC ou non spécifié
Un DateTime porte un drapeau Kind qui indique ce que l'heure signifie :
DateTime.Now.Kind; // DateTimeKind.Local
DateTime.UtcNow.Kind; // DateTimeKind.Utc
new DateTime(2026, 9, 1).Kind; // DateTimeKind.UnspecifiedDateTime.Now.Kind; // DateTimeKind.LocalDateTime.UtcNow.Kind; // DateTimeKind.Utcnew DateTime(2026, 9, 1).Kind; // DateTimeKind.UnspecifiedOn convertit entre local et UTC, ou on force le Kind sans changer les chiffres :
DateTime locale = DateTime.Now;
DateTime enUtc = locale.ToUniversalTime();
DateTime retour = enUtc.ToLocalTime();
// Marquer une valeur comme étant déjà de l'UTC (utile après lecture d'une base)
DateTime brut = new DateTime(2026, 9, 1, 12, 0, 0);
DateTime marquee = DateTime.SpecifyKind(brut, DateTimeKind.Utc);DateTime locale = DateTime.Now;DateTime enUtc = locale.ToUniversalTime();DateTime retour = enUtc.ToLocalTime(); // Marquer une valeur comme étant déjà de l'UTC (utile après lecture d'une base)DateTime brut = new DateTime(2026, 9, 1, 12, 0, 0);DateTime marquee = DateTime.SpecifyKind(brut, DateTimeKind.Utc); Unspecified est le piège : le .NET ne sait pas si c'est de l'UTC ou du local, donc une conversion peut décaler l'heure sans prévenir. Pour un instant sans ambiguïté, préfère DateTimeOffset.
# Formater en texte
DateTime d = new DateTime(2026, 9, 1, 14, 30, 0);
d.ToString("yyyy-MM-dd"); // "2026-09-01"
d.ToString("dd/MM/yyyy HH:mm"); // "01/09/2026 14:30"
d.ToString("dddd d MMMM yyyy", new CultureInfo("fr-FR")); // "mardi 1 septembre 2026"
d.ToString("o"); // "2026-09-01T14:30:00.0000000" (ISO 8601, round-trip)DateTime d = new DateTime(2026, 9, 1, 14, 30, 0); d.ToString("yyyy-MM-dd"); // "2026-09-01"d.ToString("dd/MM/yyyy HH:mm"); // "01/09/2026 14:30"d.ToString("dddd d MMMM yyyy", new CultureInfo("fr-FR")); // "mardi 1 septembre 2026"d.ToString("o"); // "2026-09-01T14:30:00.0000000" (ISO 8601, round-trip)Quelques symboles utiles : yyyy année, MM mois (01), MMMM mois en toutes lettres, dd jour (01), dddd jour de la semaine, HH heure 24h, mm minutes, ss secondes.
Pour échanger une date entre systèmes (JSON, base, API), utilise le format "o" (ISO 8601) : il est non ambigu et se re-parse sans perte.
# Parser depuis du texte
// Souple mais dépend de la culture : à réserver à une entrée maîtrisée
DateTime a = DateTime.Parse("2026-09-01");
// Robuste : ne lève pas d'exception, renvoie un bool
if (DateTime.TryParse(saisieUtilisateur, out DateTime resultat)) { /* ... */ }
// Strict : impose le format exact + une culture explicite
DateTime b = DateTime.ParseExact("01/09/2026", "dd/MM/yyyy", CultureInfo.InvariantCulture);// Souple mais dépend de la culture : à réserver à une entrée maîtriséeDateTime a = DateTime.Parse("2026-09-01"); // Robuste : ne lève pas d'exception, renvoie un boolif (DateTime.TryParse(saisieUtilisateur, out DateTime resultat)) { /* ... */ } // Strict : impose le format exact + une culture expliciteDateTime b = DateTime.ParseExact("01/09/2026", "dd/MM/yyyy", CultureInfo.InvariantCulture);TryParse est le bon réflexe pour toute donnée externe : elle est hostile par défaut, et un Parse qui échoue lève une exception.
# Bornes et ticks
DateTime.MinValue; // 0001-01-01 00:00:00
DateTime.MaxValue; // 9999-12-31 23:59:59
long ticks = d.Ticks; // nombre de "ticks" depuis MinValue
DateTime depuisTicks = new DateTime(ticks);DateTime.MinValue; // 0001-01-01 00:00:00DateTime.MaxValue; // 9999-12-31 23:59:59 long ticks = d.Ticks; // nombre de "ticks" depuis MinValueDateTime depuisTicks = new DateTime(ticks);Un tick vaut 100 nanosecondes. C'est la plus petite unité d'un DateTime, et la base de sa précision.
# La suite
- Dates et temps - le hub : quel type pour quel besoin
- DateTimeOffset et fuseaux horaires - l'instant sans ambiguïté
- TimeSpan - les durées manipulées ci-dessus