Menu

DateTime et TimeSpan en C# : Now, UtcNow, Add, soustraction, comparaison et Parse

Travailler avec les dates et heures en C# : créer des valeurs DateTime, Now, UtcNow ou Today, ajouter des jours et des mois, soustraire pour obtenir un TimeSpan, TotalHours ou Hours, comparer des dates, DayOfWeek, analyser avec ParseExact et TryParse, DateTimeOffset et DateOnly.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

System.DateTime représente une date et une heure de la journée, de l'an 1 à l'an 9999, avec une précision de 100 nanosecondes (un « tick »). System.TimeSpan représente une durée : la différence entre deux valeurs DateTime. Tous deux sont des types valeur immuables (des structs), donc chaque opération renvoie une nouvelle valeur.

Sortie :

2026-09-24 00:00:00
2026-09-24 14:30:00
14:30:05.250
2026 9 24
14:30
Thursday
267
2026-09-24 00:00
14:30:00

Chaque exemple de cette page affiche les dates avec une chaîne de format explicite. Le ToString() par défaut suit la culture courante (9/24/2026 2:30:00 PM aux États-Unis, 24.09.2026 14:30:00 en Allemagne), donc sa sortie dépend de la machine. Les codes de format se trouvent sur format DateTime.

Une date invalide lève une exception : new DateTime(2026, 2, 30) déclenche une ArgumentOutOfRangeException, tout comme le mois 13 ou l'heure 24.

Now, UtcNow et Today

Trois propriétés statiques lisent l'horloge :

Exemple de sortie :

Now:    2026-09-24 18:20:41 (Local)
UtcNow: 2026-09-24 16:20:41 (Utc)
Today:  2026-09-24 00:00:00

Dans cet exemple, le fuseau local a deux heures d'avance sur UTC, donc les deux premières lignes diffèrent de deux heures ; sur une machine réglée en UTC, elles sont identiques. La propriété Kind indique si une valeur est Local, Utc ou Unspecified (la valeur par défaut des dates que vous construisez vous-même). Utilisez DateTime.UtcNow pour tout ce que vous stockez, journalisez, comparez ou envoyez à un autre système : il ne saute pas au passage à l'heure d'été ou d'hiver, et il désigne le même instant sur chaque serveur. Convertissez en heure locale seulement pour montrer une valeur à une personne.

Pour mesurer la durée d'exécution d'un code, utilisez System.Diagnostics.Stopwatch plutôt que de soustraire deux valeurs DateTime.Now ; sa résolution est bien plus fine et il n'est pas affecté par les réglages de l'horloge.

Ajouter et soustraire du temps

AddDays, AddHours, AddMinutes, AddSeconds, AddMonths et AddYears renvoient un nouveau DateTime. Passez un nombre négatif pour revenir en arrière. Comme DateTime est immuable, le résultat doit être affecté :

Sortie :

2026-01-31
2026-02-03 09:00
2026-01-30 21:00
2026-02-28
2027-01-31
10:30
29
True

AddMonths se cale sur le dernier jour du mois quand le jour n'existe pas : le 31 janvier plus un mois donne le 28 février (ou le 29 lors d'une année bissextile), pas le 3 mars. Ajouter deux fois un mois et ajouter deux mois peuvent donc donner des dates différentes.

Soustraire des dates : TimeSpan

Soustraire un DateTime d'un autre donne un TimeSpan :

Sortie :

3.20:30:00
Days: 3, Hours: 20, Minutes: 30
TotalDays: 3.85
TotalHours: 92.5
TotalMinutes: 5550
Nights: 4

C'est la partie de l'API où l'on se trompe le plus souvent. Days, Hours, Minutes et Seconds sont les composantes de la durée (3 jours, 20 heures, 30 minutes). TotalDays, TotalHours et TotalMinutes sont la durée entière dans une seule unité, sous forme de double. « Combien d'heures le client est-il resté ? » correspond à TotalHours (92,5), pas à Hours (20).

La dernière ligne montre un point voisin : 3,85 jours se sont écoulés, mais le client est resté 4 nuits. Comparer les parties .Date compte les jours calendaires, ce que veulent en général la facturation et les affichages du type « dans n jours ».

Créer et formater des valeurs TimeSpan

Sortie :

02:15:00
01:30:00
1.12:00:00
True
03:45:00
True
02:15
36h 0m
00:00:00

TimeSpan prend en charge +, -, les comparaisons, Duration() (valeur absolue) et Negate(). Les formats personnalisés comme @"hh\:mm" exigent une barre oblique inverse devant les caractères littéraux, et hh y affiche seulement la composante des heures (0 à 23) ; pour les durées de plus d'un jour, construisez le texte à partir de TotalHours comme dans l'avant-dernière ligne.

Comparer des dates

DateTime prend en charge ==, !=, <, >, <= et >=, ainsi que CompareTo et DateTime.Compare. Pour ne comparer que la date en ignorant l'heure, comparez les propriétés .Date :

Sortie :

True
True
1
True
2026-09-01

Pour « cet horodatage tombe-t-il le 30 septembre ? », comparez avec < au début du jour suivant, comme ci-dessus. Écrire check <= end exclurait tout ce qui suit minuit le dernier jour, car end vaut 2026-09-30 00:00:00.

Les comparaisons ne regardent que les ticks, pas Kind : une valeur Local et une valeur Utc qui s'affichent de la même façon sont considérées égales alors qu'il s'agit d'instants différents. Une raison de plus de stocker les heures en UTC.

Jour de la semaine et début de semaine

DayOfWeek est un enum qui va de Sunday (0) à Saturday (6). Des calculs sur cet enum permettent de trouver les jours de semaine et les limites de semaine :

Sortie :

Thursday
4
Weekend: False
Week starts 2026-09-21 (Monday)
Next Friday: 2026-09-25
2026-09-01 to 2026-09-30

Les noms de jours affichés par DayOfWeek.ToString() sont toujours en anglais. Pour un nom localisé, formatez la date avec "dddd" et une culture.

Analyser des dates depuis des chaînes

Quand vous connaissez le format de l'entrée, utilisez ParseExact ou TryParseExact avec CultureInfo.InvariantCulture. La chaîne de format utilise les mêmes codes que le formatage :

Sortie :

2026-09-24 00:00
2026-09-24 18:05
'2026-02-28' -> Saturday, February 28
'2026-02-30' -> invalid
'28.02.2026' -> invalid
'' -> invalid
2026-02-28
2026-09-24 10:00 Utc

DateTime.Parse(text) sans format essaie de deviner avec la culture courante. "03/04/2026" est le 4 mars sur une machine américaine et le 3 avril sur une machine britannique, et une date qui s'analyse bien sur votre portable peut lever une FormatException sur un serveur. Réservez Parse aux saisies d'un utilisateur local ; utilisez ParseExact avec la culture invariante pour les fichiers, les API et les bases de données. ParseExact lève FormatException quand le texte ne correspond pas ; TryParseExact renvoie false à la place.

Calculer un âge

Soustraire des dates de naissance et diviser par 365 est faux autour des anniversaires et des années bissextiles. Comparez les années, puis corrigez si l'anniversaire de cette année n'est pas encore passé :

Sortie :

36
35
18
70 days to go

DateTimeOffset

Un DateTime n'enregistre pas son fuseau horaire au-delà du vague indicateur Kind. DateTimeOffset stocke la valeur avec son décalage par rapport à UTC, il désigne donc toujours un instant exact :

Sortie :

2026-09-24 14:00 +02:00
2026-09-24 12:00
2026-09-24 12:30
00:30:00
21:00 +09:00

Utilisez DateTimeOffset (ou des valeurs DateTime en UTC) pour les horodatages : quand une commande a été passée, quand un message a été envoyé. Les bases de données et les sérialiseurs JSON le gèrent bien. Pour convertir entre des fuseaux horaires nommés avec leurs règles d'heure d'été, utilisez TimeZoneInfo.ConvertTime ; les identifiants de fuseau diffèrent selon le système d'exploitation sur les anciennes versions de .NET ("Europe/Paris" sous Linux, "Romance Standard Time" sous Windows), et .NET 6 et plus acceptent les deux.

DateOnly et TimeOnly (.NET 6 et plus)

Beaucoup de valeurs sont une date sans heure (un anniversaire, une échéance) ou une heure sans date (des horaires d'ouverture). .NET 6 a ajouté deux types pour elles :

// .NET 6 and later
DateOnly birthday = new DateOnly(1990, 9, 24);
DateOnly due = DateOnly.FromDateTime(DateTime.Today).AddDays(14);
int daysLeft = due.DayNumber - DateOnly.FromDateTime(DateTime.Today).DayNumber;

TimeOnly opens = new TimeOnly(9, 0);
TimeOnly closes = new TimeOnly(17, 30);
bool isOpen = TimeOnly.FromDateTime(DateTime.Now).IsBetween(opens, closes);

Ils éliminent une catégorie de bugs où une heure ou un fuseau parasite décale une date d'un jour. Le code plus ancien, et le code qui cible .NET Framework ou Unity, utilise DateTime en laissant l'heure à minuit.

Erreurs courantes

  • Ignorer le résultat de AddDays. DateTime est immuable ; affectez la valeur renvoyée.
  • Utiliser Hours au lieu de TotalHours. Les composantes ne sont pas la durée totale.
  • Stocker DateTime.Now. Stockez en UTC et convertissez pour l'affichage.
  • Appeler ToString() sans format dans des logs, des fichiers ou des tests, où la sortie dépend de la culture de la machine.
  • Analyser des données de machine avec DateTime.Parse. Utilisez ParseExact et la culture invariante.
  • Confondre mm et MM dans les chaînes de format (minutes et mois). Voir format DateTime.

Questions fréquentes

Quelle est la différence entre DateTime.Now et DateTime.UtcNow ?

DateTime.Now est l'heure actuelle dans le fuseau horaire local de l'ordinateur, avec Kind à Local. DateTime.UtcNow est l'heure actuelle en UTC, avec Kind à Utc, et il est aussi plus rapide car il évite la conversion de fuseau. Stockez et comparez les horodatages en UTC, et convertissez en heure locale uniquement pour l'affichage.

Comment obtenir la différence entre deux dates en C# ?

Soustrayez-les : TimeSpan gap = end - start;. Lisez ensuite gap.TotalDays, gap.TotalHours ou gap.TotalMinutes pour la durée entière sous forme de double, ou gap.Days pour la partie en jours entiers. Pour des mois ou des années calendaires, il n'existe pas de propriété intégrée, car les mois ont des longueurs différentes ; comparez vous-même les champs année et mois.

Quelle est la différence entre TimeSpan.Hours et TotalHours ?

Hours est seulement la composante des heures, de 0 à 23, une fois les jours entiers retirés. TotalHours est la durée entière exprimée en heures, sous forme de double. Pour une durée de 1 jour et 3 heures, Hours vaut 3 et TotalHours vaut 27. Utiliser Hours là où TotalHours était voulu est un bug très courant.

Comment analyser une date depuis une chaîne en C# ?

Quand vous connaissez le format, utilisez DateTime.ParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture), ou DateTime.TryParseExact pour obtenir false au lieu d'une FormatException sur une entrée invalide. DateTime.Parse devine le format d'après la culture courante, donc 03/04/2026 signifie le 4 mars aux États-Unis et le 3 avril au Royaume-Uni.

Pourquoi AddDays ne modifie-t-il pas mon DateTime ?

DateTime est un type valeur immuable. AddDays, AddHours et les autres méthodes renvoient un nouveau DateTime et laissent l'original inchangé, vous devez donc affecter le résultat : due = due.AddDays(7);.

Quand utiliser DateTimeOffset plutôt que DateTime ?

Utilisez DateTimeOffset pour les horodatages qui doivent désigner un instant exact, comme le moment où une commande a été passée ou où une entrée de log a été écrite, surtout si les données circulent entre serveurs et fuseaux horaires. Il stocke le décalage par rapport à UTC avec la valeur. DateTime convient pour les horodatages uniquement en UTC et pour les dates sans fuseau horaire pertinent.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER