Initialisation des systèmes...

Baptiste.Dev
Retour aux notes
LangagesIntermédiaireSérie : C# / .NET

C# : DateTime en profondeur

Construire, lire, calculer, formater et parser un DateTime, et bien gérer le Kind (local, UTC, non spécifié).

Par Baptiste Vidal
4 min de lecture
Mis à jour aujourd'hui
c#csharpdatetimekindutcformatageparsing

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:00

Now 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:00

DayOfWeek 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 reculent

Soustraire 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:00

La comparaison marche avec les opérateurs habituels :

if (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.Unspecified

On 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);

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)

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);

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);

Un tick vaut 100 nanosecondes. C'est la plus petite unité d'un DateTime, et la base de sa précision.


# La suite