Conversion d’heures entre fuseaux horaires

Il devient de plus en plus important pour une application qui utilise des dates et des heures de gérer les décalages entre les fuseaux horaires. Une application ne peut plus supposer que toutes les heures puissent être exprimées selon l’heure locale, qui est l’heure fournie par la structure DateTime. Par exemple, une page web qui affiche l’heure actuelle dans la partie Est des États-Unis ne sera pas pertinente pour un client situé en Asie orientale. Cet article explique comment convertir les heures d’un fuseau horaire vers un autre, et comment convertir les valeurs DateTimeOffset qui ont une prise en charge limitée des fuseaux horaires.

Conversion en heure UTC

Le temps universel coordonné (UTC) est une norme d’heure atomique de haute précision. Les fuseaux horaires du monde sont exprimés sous forme de décalages positifs ou négatifs par rapport à l’heure UTC. L’heure UTC fournit donc une heure neutre du point de vue des fuseaux horaires. L’utilisation de l’heure UTC est recommandée lorsque la portabilité de la date et de l’heure entre les ordinateurs est importante. Pour en savoir plus et connaître d’autres bonnes pratiques d’utilisation des dates et heures, consultez Bonnes pratiques de codage avec DateTime dans .NET Framework. La conversion de fuseaux horaires individuels en heure UTC facilite les comparaisons d’heures.

Notes

Vous pouvez également sérialiser une structure DateTimeOffset pour représenter un point unique dans le temps de façon non ambiguë. Les objets DateTimeOffset stockent une valeur date-heure ainsi que son décalage par rapport à l’heure UTC. Ils représentent donc toujours un point particulier dans le temps en relation avec l’heure UTC.

Pour convertir une heure en heure UTC, le plus simple est d’appeler la méthode staticTimeZoneInfo.ConvertTimeToUtc(DateTime) (Shared en Visual Basic). La conversion exacte effectuée par cette méthode dépend de la valeur de la propriété Kind du paramètre dateTime, comme illustré dans le tableau ci-dessous :

DateTime.Kind Conversion
DateTimeKind.Local Convertit l’heure locale en heure UTC.
DateTimeKind.Unspecified Suppose que le paramètre dateTime est l’heure locale et convertit l’heure locale en heure UTC.
DateTimeKind.Utc Retourne le paramètre dateTime inchangé.

Le code suivant convertit l’heure locale actuelle en heure UTC et affiche le résultat dans la console :

DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

Si la valeur date-heure ne représente pas l’heure locale ni l’heure UTC, la méthode ToUniversalTime retournera probablement un résultat erroné. Toutefois, vous pouvez utiliser la méthode TimeZoneInfo.ConvertTimeToUtc pour convertir la date et l’heure d’un fuseau horaire spécifié. Pour plus d’informations sur la récupération d’un objet TimeZoneInfo qui représente le fuseau horaire de destination, consultez Recherche des fuseaux horaires définis sur un système Local. Le code suivant utilise la méthode TimeZoneInfo.ConvertTimeToUtc pour convertir l’heure du fuseau horaire Est en heure UTC :

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
    Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
    Console.WriteLine("The date and time are {0} UTC.", _
                      TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("Unable to find the {0} zone in the registry.", _
                      easternZoneId)
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
                      easternZoneId)
End Try

La méthode TimeZoneInfo.ConvertTimeToUtc lève ArgumentException si la propriété Kind de l’objet DateTime et le fuseau horaire sont incompatibles. Une incompatibilité se produit si la propriété Kind est DateTimeKind.Local, mais que l’objet TimeZoneInfo ne représente pas le fuseau horaire local, ou si la propriété Kind est DateTimeKind.Utc, mais que l’objet TimeZoneInfo n’est pas égal à TimeZoneInfo.Utc.

Toutes ces méthodes prennent des valeurs DateTime en paramètres et retournent une valeur DateTime. Pour les valeurs DateTimeOffset, la structure DateTimeOffset a une méthode d’instance ToUniversalTime qui convertit la date et l’heure de l’instance actuelle en heure UTC. L’exemple suivant appelle la méthode ToUniversalTime pour convertir une heure locale et plusieurs autres heures en temps universel coordonné (UTC) :

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}",
                  localTime, otherTime,
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  localTime, otherTime,
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}",
                  otherTime, universalTime,
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  otherTime, universalTime,
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

Conversion de l’heure UTC dans un fuseau horaire désigné

Pour convertir l’heure UTC en heure locale, consultez la section Conversion de l’heure UTC en heure locale qui suit. Pour convertir l’heure UTC en heure d’un fuseau horaire que vous désignez, appelez la méthode ConvertTimeFromUtc. La méthode accepte deux paramètres :

  • L’heure UTC à convertir. Ce doit être une valeur DateTime dont la propriété Kind est définie sur Unspecified ou Utc.

  • Le fuseau horaire vers lequel convertir l’heure UTC.

Le code suivant convertit l’heure UTC en heure du fuseau horaire Centre :

DateTime timeUtc = DateTime.UtcNow;
try
{
    TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
    Console.WriteLine("The date and time are {0} {1}.",
                      cstTime,
                      cstZone.IsDaylightSavingTime(cstTime) ?
                              cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}
Dim timeUtc As Date = Date.UtcNow
Try
    Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
    Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
    Console.WriteLine("The date and time are {0} {1}.", _
                      cstTime, _
                      IIf(cstZone.IsDaylightSavingTime(cstTime), _
                          cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try

Conversion de l’heure UTC en heure locale

Pour convertir une heure UTC en heure locale, appelez la méthode ToLocalTime de l’objet DateTimedont vous souhaitez convertir l’heure. Le comportement exact de cette méthode dépend de la valeur de la propriété Kind de l’objet, comme illustré dans le tableau ci-dessous :

DateTime.Kind Conversion
DateTimeKind.Local Retourne la valeur DateTime inchangée.
DateTimeKind.Unspecified Suppose que la valeur DateTime est une heure UTC et convertit l’heure UTC en heure locale.
DateTimeKind.Utc Convertit la valeur DateTime en heure locale.

Notes

La méthode TimeZone.ToLocalTime se comporte comme la méthode DateTime.ToLocalTime. Elle prend un seul paramètre, qui est la valeur date-heure à convertir.

Vous pouvez également convertir l’heure de n’importe quel fuseau horaire désigné en heure locale à l’aide de la méthode staticTimeZoneInfo.ConvertTime (Shared en Visual Basic). Cette technique est abordée dans la section suivante.

Conversion entre deux fuseaux horaires quelconques

Vous pouvez convertir une heure d’un fuseau horaire à un autre en utilisant l’une des deux méthodes static suivantes (Shared en Visual Basic) de la classe TimeZoneInfo :

  • ConvertTime

    Les paramètres de cette méthode sont la valeur date-heure à convertir, un objet TimeZoneInfo qui représente le fuseau horaire de la valeur date-heure, et un objet TimeZoneInfo qui représente le fuseau horaire dans lequel convertir la valeur date-heure.

  • ConvertTimeBySystemTimeZoneId

    Les paramètres de cette méthode sont la valeur date-heure à convertir, l’identificateur du fuseau horaire de la valeur date-heure et l’identificateur du fuseau horaire dans lequel convertir la valeur date-heure.

Les deux méthodes exigent que la propriété Kind de la valeur date-heure à convertir et l’objet TimeZoneInfo ou l’identificateur de fuseau horaire qui représente son fuseau horaire correspondent. Sinon, une exception ArgumentException est levée. Par exemple, si la propriété Kind de la valeur date-heure est DateTimeKind.Local, une exception est levée si l’objet TimeZoneInfo passé comme paramètre à la méthode n’est pas égal à TimeZoneInfo.Local. Une exception est également levée si l’identificateur passé comme paramètre à la méthode n’est pas égal à TimeZoneInfo.Local.Id.

L’exemple suivant utilise la méthode ConvertTime pour convertir l’heure d’Hawaï en heure locale :

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
    TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
    Console.WriteLine("{0} {1} is {2} local time.",
            hwTime,
            hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
            TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.");
}
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
    Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
    Console.WriteLine("{0} {1} is {2} local time.", _
                      hwTime, _
                      IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                      TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try

Conversion de valeurs DateTimeOffset

Les valeurs date-heure représentées par les objets DateTimeOffset ont une prise en charge limitée des fuseaux horaires, car l’objet est dissocié de son fuseau horaire au moment de son instanciation. Toutefois, dans beaucoup de cas, une application doit simplement convertir une date et une heure en fonction de deux décalages différents par rapport à l’heure UTC plutôt qu’en fonction de l’heure dans des fuseaux horaires particuliers. Pour effectuer cette conversion, vous pouvez appeler la méthode ToOffset de l’instance actuelle. Le seul paramètre de la méthode est le décalage de la nouvelle valeur date-heure que la méthode retourne.

Par exemple, si la valeur date-heure d’une demande de page web faite par un utilisateur est connue et est sérialisée en chaîne au format MM/jj/aaaa hh:mm:ss zzzz, la méthode ReturnTimeOnServer qui suit convertit cette valeur date-heure en date et heure sur le serveur web :

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"
    Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Si la méthode passe la chaîne "9/1/2007 5:32:07 -05:00", qui représente la date et l’heure dans un fuseau horaire en retard de cinq heures par rapport à l’heure UTC, elle retourne "9/1/2007 3:32:07 AM -07:00" pour un serveur situé dans le fuseau horaire Pacifique des États-Unis.

La classe TimeZoneInfo inclut aussi une surcharge de la méthode TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) qui effectue des conversions de fuseau horaire avec des valeurs ToOffset(TimeSpan). Les paramètres de la méthode sont une valeur DateTimeOffset et une référence au fuseau horaire dans lequel l’heure est convertie. L’appel de méthode retourne une valeur DateTimeOffset. Par exemple, la méthode ReturnTimeOnServer de l’exemple précédent peut être réécrite comme suit pour appeler la méthode ConvertTime(DateTimeOffset, TimeZoneInfo).

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Voir aussi