Konwertowanie czasów między strefami czasowymi

Staje się coraz ważniejsza dla każdej aplikacji, która współpracuje z datami i godzinami, aby obsługiwać różnice między strefami czasowymi. Aplikacja nie może już zakładać, że wszystkie czasy można wyrazić w czasie lokalnym, co jest czasem dostępnym DateTime ze struktury. Na przykład strona internetowa, która wyświetla bieżącą godzinę we wschodniej części Stany Zjednoczone, nie będzie wiarygodna dla klienta we wschodniej Azji. W tym artykule wyjaśniono, jak konwertować czasy z jednej strefy czasowej na inną i konwertować DateTimeOffset wartości, które mają ograniczoną świadomość strefy czasowej.

Konwertowanie na uniwersalny czas koordynowany

Uniwersalny czas koordynowany (UTC) to wysoki, niepodzielne standard czasu. Strefy czasowe świata są wyrażane jako dodatnie lub ujemne przesunięcia z czasu UTC. W związku z tym czas UTC zapewnia strefę czasową wolnego lub neutralnego czasu strefy czasowej. Użycie czasu UTC jest zalecane, gdy ważna jest przenośność daty i godziny na komputerach. Aby uzyskać szczegółowe informacje i inne najlepsze rozwiązania dotyczące korzystania z dat i godzin, zobacz Kodowanie najlepszych rozwiązań dotyczących używania daty/godziny w programie .NET Framework. Konwertowanie poszczególnych stref czasowych na czas UTC sprawia, że porównania czasu są łatwe.

Uwaga

Można również serializować DateTimeOffset strukturę, aby reprezentować pojedynczy punkt w czasie jednoznacznie. Ponieważ DateTimeOffset obiekty przechowują wartość daty i godziny wraz z przesunięciem od CZASU UTC, zawsze reprezentują określony punkt w czasie w odniesieniu do czasu UTC.

Najprostszym sposobem przekonwertowania czasu na utc jest wywołanie static metody (Shared w Visual Basic). TimeZoneInfo.ConvertTimeToUtc(DateTime) Dokładna konwersja wykonywana przez metodę zależy od wartości dateTime właściwości parametru Kind , jak pokazano w poniższej tabeli:

DateTime.Kind Konwersja
DateTimeKind.Local Konwertuje czas lokalny na czas UTC.
DateTimeKind.Unspecified Przyjęto założenie, dateTime że parametr jest czasem lokalnym i konwertuje czas lokalny na czas UTC.
DateTimeKind.Utc dateTime Zwraca parametr bez zmian.

Poniższy kod konwertuje bieżący czas lokalny na czas UTC i wyświetla wynik w konsoli:

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

Jeśli wartość daty i godziny nie reprezentuje czasu lokalnego ani czasu UTC, ToUniversalTime metoda prawdopodobnie zwróci błędny wynik. Można jednak użyć TimeZoneInfo.ConvertTimeToUtc metody , aby przekonwertować datę i godzinę z określonej strefy czasowej. Aby uzyskać szczegółowe informacje na temat pobierania TimeZoneInfo obiektu reprezentującego docelową strefę czasową, zobacz Znajdowanie stref czasowych zdefiniowanych w systemie lokalnym. Poniższy kod używa TimeZoneInfo.ConvertTimeToUtc metody , aby przekonwertować wschodni czas standardowy na 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

Metoda TimeZoneInfo.ConvertTimeToUtc zgłasza błąd ArgumentException , jeśli DateTime właściwość obiektu Kind i strefa czasowa są niezgodne. Niezgodność występuje, jeśli właściwość jestDateTimeKind.Local, ale TimeZoneInfo obiekt nie reprezentuje lokalnej strefy czasowej lub jeśli Kind właściwość jestDateTimeKind.Utc, ale TimeZoneInfo obiekt nie jest równy TimeZoneInfo.Utc.Kind

Wszystkie te metody przyjmują DateTime wartości jako parametry i zwracają DateTime wartość. Dla DateTimeOffset wartości struktura DateTimeOffset ma metodę ToUniversalTime wystąpienia, która konwertuje datę i godzinę bieżącego wystąpienia na UTC. Poniższy przykład wywołuje metodę ToUniversalTime , aby przekonwertować czas lokalny i kilka innych razy na 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   

Konwertowanie czasu UTC na wyznaczoną strefę czasową

Aby przekonwertować czas UTC na lokalny, zobacz sekcję Konwertowanie czasu UTC na czas lokalny, która jest następująca. Aby przekonwertować czas UTC na czas w dowolnej wyznaczonej strefie czasowej, wywołaj metodę ConvertTimeFromUtc . Metoda przyjmuje dwa parametry:

  • Czas UTC do konwersji. Musi to być DateTime wartość, której Kind właściwość jest ustawiona na Unspecified lub Utc.

  • Strefa czasowa, na która ma być konwertowana utc.

Poniższy kod konwertuje czas UTC na środkowy czas standardowy:

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

Konwertowanie czasu UTC na czas lokalny

Aby przekonwertować czas UTC na lokalny, wywołaj ToLocalTime metodę DateTime obiektu, którego czas chcesz przekonwertować. Dokładne zachowanie metody zależy od wartości właściwości obiektu Kind , jak pokazano w poniższej tabeli:

DateTime.Kind Konwersja
DateTimeKind.Local DateTime Zwraca wartość bez zmian.
DateTimeKind.Unspecified Przyjęto założenie, że DateTime wartość to UTC i konwertuje czas UTC na czas lokalny.
DateTimeKind.Utc Konwertuje DateTime wartość na czas lokalny.

Uwaga

Metoda TimeZone.ToLocalTime zachowuje się identycznie z DateTime.ToLocalTime metodą . Do przekonwertowania przyjmuje jeden parametr, który jest wartością daty i godziny.

Możesz również przekonwertować czas w dowolnej wyznaczonej strefie czasowej na czas lokalny przy użyciu static metody (Shared w Visual Basic). TimeZoneInfo.ConvertTime Ta technika została omówiona w następnej sekcji.

Konwertowanie między dowolnymi dwiema strefami czasowymi

Można przekonwertować między dwiema strefami czasowymi przy użyciu jednej z następujących dwóch static metod TimeZoneInfo (Sharedw Visual Basic) klasy:

  • ConvertTime

    Parametry tej metody to wartość daty i godziny do przekonwertowania, TimeZoneInfo obiekt reprezentujący strefę czasową wartości daty i godziny oraz TimeZoneInfo obiekt reprezentujący strefę czasową, na którą ma być konwertowana wartość daty i godziny.

  • ConvertTimeBySystemTimeZoneId

    Parametry tej metody to wartość daty i godziny, która ma być konwertowana, identyfikator strefy czasowej wartości daty i godziny oraz identyfikator strefy czasowej w celu przekonwertowania wartości daty i godziny na.

Obie metody wymagają, aby Kind właściwość wartości daty i godziny przekonwertowała TimeZoneInfo obiekt lub identyfikator strefy czasowej reprezentujący jej strefę czasową. W przeciwnym razie zgłaszany jest element ArgumentException . Jeśli na przykład Kind właściwość wartości daty i godziny to DateTimeKind.Local, wyjątek jest zgłaszany, jeśli TimeZoneInfo obiekt przekazany jako parametr do metody nie jest równy TimeZoneInfo.Local. Wyjątek jest również zgłaszany, jeśli identyfikator przekazany jako parametr do metody nie jest równy TimeZoneInfo.Local.Id.

W poniższym przykładzie użyto ConvertTime metody do przekonwertowania z hawajskiego czasu standardowego na czas lokalny:

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

Konwertowanie wartości DateTimeOffset

Wartości daty i godziny reprezentowane przez DateTimeOffset obiekty nie są w pełni świadome strefy czasowej, ponieważ obiekt jest odłączony od strefy czasowej w momencie utworzenia wystąpienia. Jednak w wielu przypadkach aplikacja musi po prostu przekonwertować datę i godzinę na podstawie dwóch różnych przesunięć od UTC, a nie czasu w określonych strefach czasowych. Aby wykonać tę konwersję, możesz wywołać metodę bieżącego ToOffset wystąpienia. Pojedynczy parametr metody jest przesunięciem nowej wartości daty i godziny zwracanej przez metodę.

Jeśli na przykład data i godzina żądania użytkownika dla strony internetowej jest znana i jest serializowana jako ciąg w formacie MM/dd/rrrr hh:mm:ss zzzz, następująca ReturnTimeOnServer metoda konwertuje tę wartość daty i godziny na datę i godzinę na serwerze internetowym:

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

Jeśli metoda przekazuje ciąg "9/1/2007 5:32:07 -05:00", który reprezentuje datę i godzinę w strefie czasowej pięć godzin wcześniej niż UTC, zwraca wartość "9/1/2007 3:32:07 AM -07:00" dla serwera znajdującego się w strefie czasowej Pacyficznej Stanów Zjednoczonych.

Klasa TimeZoneInfo zawiera również przeciążenie TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) metody, która wykonuje konwersje strefy czasowej z wartościami ToOffset(TimeSpan) . Parametry metody są wartością DateTimeOffset i odwołaniem do strefy czasowej, do której ma zostać przekonwertowany czas. Wywołanie metody zwraca DateTimeOffset wartość. Na przykład ReturnTimeOnServer metoda w poprzednim przykładzie może zostać przepisana w następujący sposób, aby wywołać metodę 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

Zobacz też