Share via


Choix entre DateTime, DateTimeOffset et TimeZoneInfo

Mise à jour : novembre 2007

De nombreuses applications .NET Framework utilisent des informations sur la date et l'heure, et ce de différentes façons. Ces informations sur la date et l'heure sont le plus fréquemment employées dans les cas suivants :

  • pour indiquer une date uniquement, sans accorder d'importance aux informations sur l'heure ;

  • pour indiquer une heure uniquement, sans accorder d'importance aux informations sur la date ;

  • pour indiquer une date et une heure abstraites qui ne sont pas liées à une date, à une heure et à un lieu spécifiques (par exemple, la plupart des magasins d'une chaîne internationale ouvrent en semaine à 9 h 00 le matin).

  • pour récupérer des informations sur la date et l'heure à partir de sources extérieures au .NET Framework, les informations sur la date et l'heure étant généralement stockées dans un type de données simple ;

  • pour identifier de manière spécifique et univoque un point unique dans le temps. Certaines applications exigent que la date et l'heure soient univoques uniquement sur le système hôte, tandis que d'autres applications exigent qu'elles soient univoques sur l'ensemble des systèmes (en d'autres termes, une date sérialisée sur un système peut être valablement désérialisée et utilisée sur un autre système quel que soit l'endroit dans le monde).

  • pour conserver plusieurs heures liées (telles que l'heure locale du demandeur et l'heure de réception d'une requête Web du serveur) ;

  • pour appliquer l'arithmétique de date et d'heure, avec un résultat qui identifie de manière spécifique et univoque un point unique dans le temps le cas échéant.

Le .NET Framework inclut les types DateTime, DateTimeOffsetet TimeZoneInfo, chacun pouvant être utilisé pour générer des applications qui fonctionnent avec des dates et des heures.

Remarque :

Cette rubrique ne traite pas d'un quatrième type, TimeZone, car la plupart de ses fonctionnalités sont incorporées à la classe TimeZoneInfo. Les développeurs doivent, dans la mesure du possible, utiliser la classe TimeZoneInfo plutôt que la classe TimeZone.

Structure DateTime

Une valeur DateTime définit une date et une heure données. Depuis sa version 2.0, le .NET Framework inclut une propriété Kind qui fournit des informations limitées sur le fuseau horaire dont cette date et cette heure font partie. La valeur DateTimeKind retournée par la propriété Kind indique si la valeur DateTime représente l'heure locale (DateTimeKind.Local), le temps universel coordonné (UTC, Coordinated Universal Time) (DateTimeKind.Utc) ou une heure non spécifiée (DateTimeKind.Unspecified).

La structure DateTime convient aux applications qui effectuent les opérations suivantes :

  • utilisation de dates uniquement ;

  • utilisation d'heures uniquement ;

  • utilisation de dates et d'heures abstraites ;

  • récupération d'informations sur la date et l'heure à partir de sources extérieures au .NET Framework, telles que des bases de données SQL. En règle générale, ces sources stockent des informations sur la date et l'heure dans un format simple qui est compatible avec la structure DateTime.

  • application de l'arithmétique de date et d'heure, tout en s'intéressant aux résultats généraux. Par exemple, lors d'une opération d'addition qui ajoute six mois à une date et à une heure données, l'ajustement ou non du résultat à l'heure d'été ne présente souvent pas d'importance.

À moins qu'une valeur DateTime particulière ne représente l'heure UTC, cette valeur de date et d'heure est souvent équivoque ou limitée au niveau de sa portabilité. Par exemple, si une valeur DateTime représente l'heure locale, celle-ci est alors portable dans le fuseau horaire local concerné (en d'autres termes, si la valeur est désérialisée sur un autre système dans le même fuseau horaire, cette valeur continue à identifier de manière univoque un point unique dans le temps). En dehors de ce fuseau horaire local, cette valeur DateTime peut être interprétée de plusieurs façons. Si la propriété Kind de la valeur est DateTimeKind.Unspecified, elle est alors encore moins portable : elle est désormais équivoque dans le même fuseau horaire voire même sur le système sur lequel elle a été initialement sérialisée. C'est uniquement lorsqu'une valeur DateTime représente l'heure UTC que cette valeur identifie de manière univoque un point unique dans le temps, quel que soit le système ou le fuseau horaire dans lequel la valeur est utilisée.

Remarque importante :

Lors de l'enregistrement ou du partage de données DateTime, l'heure UTC doit être utilisée et la propriété Kind de la valeur DateTime doit avoir la valeur DateTimeKindUTC().

Structure DateTimeOffset

La structure DateTimeOffset représente une valeur de date et d'heure, ainsi qu'un décalage qui indique l'écart entre cette valeur et l'heure UTC. La valeur continue par conséquent à identifier de manière univoque un point unique dans le temps.

Même si le type DateTimeOffset inclut la plupart des fonctionnalités du type DateTime, il n'est pas censé remplacer le type DateTime lors du développement d'applications. Il convient plutôt aux applications qui effectuent les opérations suivantes :

  • identification de manière spécifique et univoque d'un point unique dans le temps. Le type DateTimeOffset permet de définir de manière univoque le sens de « maintenant » et d'enregistrer l'heure de transactions, l'heure d'événements système ou d'événements d'application et l'heure de création et de modification de fichiers.

  • application de l'arithmétique de date et d'heure générale ;

  • conservation de plusieurs heures liées, à partir du moment où ces heures sont stockées sous forme de deux valeurs séparées ou de deux membres d'une structure.

Remarque :

Ces cas d'emploi des valeurs DateTimeOffset sont beaucoup plus courants que ceux des valeurs DateTime. DateTimeOffset doit par conséquent être considéré comme le type de date et d'heure par défaut lors du développement d'applications.

Une valeur DateTimeOffset n'est pas liée à un fuseau horaire en particulier, mais elle peut découler de l'un des nombreux fuseaux horaires. Pour illustrer ce propos, les fuseaux horaires dont plusieurs valeurs DateTimeOffset (y compris une heure normale du Pacifique locale) peuvent faire partie sont listés dans l'exemple suivant.

Imports System.Collections.ObjectModel

Module TimeOffsets
   Public Sub Main()
      Dim thisTime As DateTimeOffset 

      thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
      ShowPossibleTimeZones(thisTime) 

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))  
      ShowPossibleTimeZones(thisTime)

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
      ShowPossibleTimeZones(thisTime)
   End Sub

   Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
      Dim offset As TimeSpan = offsetTime.Offset
      Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

      Console.WriteLine("{0} could belong to the following time zones:", _
                        offsetTime.ToString())
      ' Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones()     
      ' Iterate time zones
      For Each timeZone As TimeZoneInfo In timeZones
         ' Compare offset with offset for that date in that time zone
         If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
            Console.WriteLine("   {0}", timeZone.DisplayName)
         End If   
      Next
      Console.WriteLine()
   End Sub
End Module
' This example displays the following output to the console:
'       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
'          (GMT-07:00) Arizona
'          (GMT-08:00) Pacific Time (US & Canada)
'          (GMT-08:00) Tijuana, Baja California
'       
'       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
'          (GMT-06:00) Central America
'          (GMT-06:00) Central Time (US & Canada)
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
'          (GMT-06:00) Saskatchewan
'       
'       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
'          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
'          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
'          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
'          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
'          (GMT+01:00) West Central Africa
using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;

      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));  
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;

      Console.WriteLine("{0} could belong to the following time zones:", 
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();     
      // Iterate time zones 
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   } 
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//       
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//       
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa

Le résultat indique que chaque valeur de date et d'heure donnée dans cet exemple peut faire partie d'au moins trois fuseaux horaires différents. La valeur DateTimeOffset de 6/10/2007 indique que si une valeur de date et d'heure représente une heure d'été, son décalage par rapport à l'heure UTC ne correspond alors pas nécessairement au décalage de l'offset UTC de base du fuseau horaire d'origine ni au décalage par rapport à l'heure UTC mentionnée dans son nom d'affichage. Comme une valeur DateTimeOffset unique n'est pas fortement couplée avec son fuseau horaire, elle ne peut pas indiquer le passage à l'heure d'été ou d'hiver d'un fuseau horaire. Cela peut s'avérer particulièrement problématique lorsque l'arithmétique de date et d'heure est utilisée pour manipuler une valeur DateTimeOffset. (Pour plus d'informations sur l'application de l'arithmétique de date et d'heure de manière à prendre en compte les règles d'ajustement d'un fuseau horaire, consultez Exécution d'opérations arithmétiques avec des dates et heures.)

Classe TimeZoneInfo

La classe TimeZoneInfo représente les fuseaux horaires dans le monde et permet la conversion de toute date et heure d'un fuseau horaire à un autre. La classe TimeZoneInfo peut utiliser des dates et des heures de telle sorte que toute valeur de date et d'heure puisse identifier de manière univoque un point unique dans le temps. La classe TimeZoneInfo est également extensible. Même si elle dépend des informations sur les fuseaux horaires fournies par les systèmes Windows et définies dans le Registre, elle prend en charge la création de fuseaux horaires personnalisés. Elle prend également en charge la sérialisation et désérialisation d'informations sur les fuseaux horaires.

Dans certains cas, un travail de développement plus poussé peut s'avérer nécessaire pour tirer pleinement parti de la classe TimeZoneInfo. En premier lieu, les valeurs de date et d'heure ne sont pas fortement couplées avec les fuseaux horaires dont elles font partie. À moins que votre application ne dispose d'un mécanisme permettant de lier une date et une heure au fuseau horaire qui y est associé, une valeur de date et d'heure donnée peut par conséquent facilement se dissocier de son fuseau horaire. (Pour lier ces informations, une méthode consiste à définir une classe ou une structure qui contient à la fois la valeur de date et d'heure et l'objet de fuseau horaire qui y est associé.) En second lieu, Windows XP et des versions antérieures de Windows ne prennent pas vraiment en charge l'historique des informations sur les fuseaux horaires et Windows Vista n'en assure qu'une prise en charge limitée. Les applications qui sont conçues pour gérer l'historique de dates et d'heures doivent largement recourir aux fuseaux horaires personnalisés.

Pour tirer parti de la prise en charge des fuseaux horaires dans le .NET Framework, le fuseau horaire dont une valeur de date et d'heure fait partie doit être connu lors de l'instanciation de cet objet de date et d'heure. Ce n'est souvent pas le cas, notamment dans les applications Web ou réseau.

Voir aussi

Autres ressources

Heures et fuseaux horaires