Share via


Comment : utiliser des fuseaux horaires en arithmétique de date et heure

Mise à jour : novembre 2007

Généralement, lorsque vous effectuez des opérations arithmétiques de date et heure à l'aide des valeurs DateTime ou DateTimeOffset, le résultat ne reflète aucune règle d'ajustement de fuseau horaire. Cela est vrai même lorsque le fuseau horaire de la valeur de date et d'heure est clairement identifiable (par exemple, lorsque la propriété Kind a la valeur Local). Cette rubrique indique comment exécuter des opérations arithmétiques sur des valeurs de date et d'heure qui appartiennent à un fuseau horaire particulier. Les résultats des opérations arithmétiques refléteront les règles d'ajustement du fuseau horaire.

Pour appliquer des règles d'ajustement à l'arithmétique de date et heure

  1. Implémentez une méthode permettant de coupler fortement une valeur de date et d'heure avec le fuseau horaire auquel elle appartient. Par exemple, déclarez une structure qui inclut la valeur de date et d'heure et son fuseau horaire. L'exemple suivant utilise cette approche pour lier une valeur DateTime à son fuseau horaire.

    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
       Dim TimeZone As TimeZoneInfo
       Dim Time As Date
    End Structure
    
    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
       TimeZoneInfo TimeZone;
       DateTime Time;
    }
    
  2. Convertissez une heure en temps universel coordonné (UTC, Coordinated Universal Time) en appelant la méthode ConvertTimeToUtc ou la méthode ConvertTime.

  3. Exécutez l'opération arithmétique sur l'heure UTC.

  4. Convertissez l'heure UTC en un fuseau horaire associé à l'heure d'origine en appelant la méthode TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo).

Exemple

L'exemple suivant ajoute deux heures et trente minutes au 9 mars 2008, à 1h30 du matin, heure du Centre (des États-Unis). Dans ce fuseau horaire, le passage à l'heure d'été a lieu trente minutes plus tard, à 2h00 du matin, le 9 mars 2008. Comme cet exemple suit les quatre étapes répertoriées dans la section précédente, l'heure correcte qui est affichée est 5h00 du matin, le 9 mars 2008.

Public Structure TimeZoneTime
   Public TimeZone As TimeZoneInfo
   Public Time As Date

   Public Sub New(tz As TimeZoneInfo, time As Date)
      If tz Is Nothing Then _
         Throw New ArgumentNullException("The time zone cannot be a null reference.")

      Me.TimeZone = tz
      Me.Time = time
   End Sub

   Public Function AddTime(interval As TimeSpan) As TimeZoneTime
      ' Convert time to UTC
      Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
                                                              Me.TimeZone)      
      ' Add time interval to time
      utcTime = utcTime.Add(interval)
      ' Convert time back to time in time zone
      Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
                              TimeZoneInfo.Utc, Me.TimeZone))
   End Function
End Structure

Module TimeArithmetic
   Public Const tzName As String = "Central Standard Time"

   Public Sub Main()
      Try
         Dim cstTime1, cstTime2 As TimeZoneTime

         Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
         Dim time1 As Date = #03/09/2008 1:30AM#
         Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

         cstTime1 = New TimeZoneTime(cst, time1)
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                    twoAndAHalfHours.ToString(), _ 
                                                    cstTime2.Time)  
      Catch
         Console.WriteLine("Unable to find {0}.", tzName)
      End Try   
   End Sub   
End Module
using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTime Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTime time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, 
                              TimeZoneInfo.Utc, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, time1);
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

Les valeurs DateTime et DateTimeOffset sont dissociées de tout fuseau horaire auquel elles peuvent appartenir. Pour exécuter des opérations arithmétiques de date et heure qui appliquent automatiquement les règles d'ajustement d'un fuseau horaire, le fuseau horaire auquel toute valeur de date et d'heure appartient doit être immédiatement identifiable. Cela signifie qu'une date et une heure, ainsi que le fuseau horaire associé, doivent être fortement couplés. Vous disposez de plusieurs méthodes pour y parvenir, comme celles décrites ci-dessous.

  • Supposez que toutes les heures utilisées dans une application appartiennent à un fuseau horaire particulier. Bien qu'appropriée dans certains cas, cette approche présente une souplesse et une portabilité limitées.

  • Définissez un type qui couple fortement une date et une heure avec le fuseau horaire associé en les incluant en tant que champs du type. Cette approche est utilisée dans l'exemple de code qui définit une structure permettant de stocker la date et l'heure, ainsi que le fuseau horaire, dans deux champs membre.

L'exemple illustre comment exécuter des opérations arithmétiques sur les valeurs DateTime pour appliquer les règles d'ajustement de fuseau horaire au résultat. Les valeurs DateTimeOffset peuvent tout aussi bien être utilisées. L'exemple suivant illustre comment le code de l'exemple d'origine peut être adapté pour utiliser DateTimeOffset au lieu de DateTime.

Public Structure TimeZoneTime
   Public TimeZone As TimeZoneInfo
   Public Time As DateTimeOffset

   Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
      If tz Is Nothing Then _
         Throw New ArgumentNullException("The time zone cannot be a null reference.")

      Me.TimeZone = tz
      Me.Time = time
   End Sub

   Public Function AddTime(interval As TimeSpan) As TimeZoneTime
      ' Convert time to UTC
      Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)      
      ' Add time interval to time
      utcTime = utcTime.Add(interval)
      ' Convert time back to time in time zone
      Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
   End Function
End Structure

Module TimeArithmetic
   Public Const tzName As String = "Central Standard Time"

   Public Sub Main()
      Try
         Dim cstTime1, cstTime2 As TimeZoneTime

         Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
         Dim time1 As Date = #03/09/2008 1:30AM#
         Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

         cstTime1 = New TimeZoneTime(cst, _
                        New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                    twoAndAHalfHours.ToString(), _ 
                                                    cstTime2.Time)  
      Catch
         Console.WriteLine("Unable to find {0}.", tzName)
      End Try   
   End Sub   
End Module
using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTimeOffset Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);      
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, 
                        new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

Notez que si cet ajout est appliqué à la valeur DateTimeOffset alors qu'elle n'a pas été préalablement convertie en heure UTC, le résultat indique le point correct dans le temps, mais son offset ne reflète pas celui du fuseau horaire désigné pour cette heure.

Compilation du code

Cet exemple nécessite :

  • qu'une référence à System.Core.dll soit ajoutée au projet ;

  • que l'espace de noms System soit importé avec l'instruction using (requise en code C#).

Voir aussi

Concepts

Exécution d'opérations arithmétiques avec des dates et heures

Autres ressources

Heures et fuseaux horaires