Konvertera tider mellan tidszoner

Det blir allt viktigare för alla program som fungerar med datum och tider för att hantera skillnader mellan tidszoner. Ett program kan inte längre anta att alla tider kan uttryckas i den lokala tiden, vilket är den tid som är tillgänglig från DateTime strukturen. En webbsida som till exempel visar aktuell tid i den östra delen av USA kommer att sakna trovärdighet för en kund i östra Asien. Den här artikeln beskriver hur du konverterar tider från en tidszon till en annan och konverterar DateTimeOffset värden som har begränsad tidszonsmedvetenhet.

Konvertera till samordnad universell tid

Coordinated Universal Time (UTC) är en atomisk tidsstandard med hög precision. Världens tidszoner uttrycks som positiva eller negativa förskjutningar från UTC. UTC tillhandahåller därför en tidszonsfri eller tidszonsneutral tid. Användning av UTC rekommenderas när ett datum och en tids portabilitet mellan datorer är viktig. Mer information och andra metodtips med datum och tider finns i Metodtips för kodning med DateTime i .NET Framework. Om du konverterar enskilda tidszoner till UTC blir det enkelt att göra tidsjämförelser.

Kommentar

Du kan också serialisera en DateTimeOffset struktur så att den representerar en enskild tidpunkt entydigt. Eftersom DateTimeOffset objekt lagrar ett datum- och tidsvärde tillsammans med dess förskjutning från UTC representerar de alltid en viss tidpunkt i förhållande till UTC.

Det enklaste sättet att konvertera en tid till UTC är att anropa static metoden (Shared i Visual Basic). TimeZoneInfo.ConvertTimeToUtc(DateTime) Den exakta konvertering som utförs av metoden beror på värdet för dateTime parameterns Kind egenskap, som följande tabell visar:

DateTime.Kind Konvertering
DateTimeKind.Local Konverterar lokal tid till UTC.
DateTimeKind.Unspecified Förutsätter att parametern dateTime är lokal tid och konverterar lokal tid till UTC.
DateTimeKind.Utc Returnerar parametern dateTime oförändrad.

Följande kod konverterar den aktuella lokala tiden till UTC och visar resultatet för konsolen:

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

Om datum- och tidsvärdet inte representerar den lokala tiden eller UTC ToUniversalTime returnerar metoden sannolikt ett felaktigt resultat. Du kan dock använda TimeZoneInfo.ConvertTimeToUtc metoden för att konvertera datum och tid från en angiven tidszon. Mer information om hur du hämtar ett TimeZoneInfo objekt som representerar måltidszonen finns i Hitta de tidszoner som definierats i ett lokalt system. Följande kod använder TimeZoneInfo.ConvertTimeToUtc metoden för att konvertera Eastern Standard Time till 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

Metoden TimeZoneInfo.ConvertTimeToUtc genererar ett ArgumentException om DateTime objektets Kind egenskap och tidszonen är felmatchad. Ett matchningsfel inträffar om Kind egenskapen är DateTimeKind.Local men TimeZoneInfo objektet inte representerar den lokala tidszonen Kind , eller om egenskapen är DateTimeKind.Utc men TimeZoneInfo objektet inte är lika med TimeZoneInfo.Utc.

Alla dessa metoder tar DateTime värden som parametrar och returnerar ett DateTime värde. För DateTimeOffset värden DateTimeOffset har strukturen en ToUniversalTime instansmetod som konverterar datum och tid för den aktuella instansen till UTC. I följande exempel anropas ToUniversalTime metoden för att konvertera en lokal tid och flera andra gånger till 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   

Konvertera UTC till en angiven tidszon

Information om hur du konverterar UTC till lokal tid finns i avsnittet Konvertera UTC till lokal tid som följer. Om du vill konvertera UTC till tiden i en tidszon som du anger anropar ConvertTimeFromUtc du metoden. Metoden tar två parametrar:

  • UTC som ska konverteras. Detta måste vara ett DateTime värde vars Kind egenskap är inställd på Unspecified eller Utc.

  • Tidszonen som UTC ska konverteras till.

Följande kod konverterar UTC till central standardtid:

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

Konvertera UTC till lokal tid

Om du vill konvertera UTC till lokal tid anropar ToLocalTime du metoden för objektet DateTime vars tid du vill konvertera. Metodens exakta beteende beror på värdet för objektets Kind egenskap, som följande tabell visar:

DateTime.Kind Konvertering
DateTimeKind.Local Returnerar värdet DateTime oförändrat.
DateTimeKind.Unspecified Förutsätter att värdet DateTime är UTC och konverterar UTC till lokal tid.
DateTimeKind.Utc Konverterar värdet DateTime till lokal tid.

Kommentar

Metoden TimeZone.ToLocalTime beter sig identiskt med DateTime.ToLocalTime metoden. Det krävs en enskild parameter, som är datum- och tidsvärdet, för att konvertera.

Du kan också konvertera tiden i en angiven tidszon till lokal tid med hjälp static av metoden (Shared i Visual Basic). TimeZoneInfo.ConvertTime Den här tekniken beskrivs i nästa avsnitt.

Konvertera mellan två tidszoner

Du kan konvertera mellan två tidszoner med någon av följande två static metoder (Shared i Visual Basic) i TimeZoneInfo klassen:

  • ConvertTime

    Den här metodens parametrar är det datum- och tidsvärde som ska konverteras, ett TimeZoneInfo objekt som representerar tidszonen för datum- och tidsvärdet och ett TimeZoneInfo objekt som representerar tidszonen som datum- och tidsvärdet ska konverteras till.

  • ConvertTimeBySystemTimeZoneId

    Den här metodens parametrar är det datum- och tidsvärde som ska konverteras, identifieraren för datum- och tidsvärdets tidszon och identifieraren för tidszonen som datum- och tidsvärdet ska konverteras till.

Båda metoderna kräver att Kind egenskapen för datum- och tidsvärdet konverteras och objektet eller tidszonsidentifieraren som representerar tidszonen TimeZoneInfo motsvarar varandra. Annars kastas en ArgumentException . Om Kind egenskapen för datum- och tidsvärdet till exempel är DateTimeKind.Localgenereras ett undantag om TimeZoneInfo objektet som skickas som en parameter till metoden inte är lika med TimeZoneInfo.Local. Ett undantag utlöses också om identifieraren som skickas som en parameter till metoden inte är lika med TimeZoneInfo.Local.Id.

I följande exempel används ConvertTime metoden för att konvertera från Hawaiian Standard Time till lokal tid:

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

Konvertera DateTimeOffset-värden

Datum- och tidsvärden som representeras av DateTimeOffset objekt är inte helt tidszonsmedvetna eftersom objektet kopplas från tidszonen när det instansieras. I många fall behöver dock ett program helt enkelt konvertera ett datum och en tid baserat på två olika förskjutningar från UTC i stället för på tid i vissa tidszoner. Om du vill utföra den här konverteringen kan du anropa den aktuella instansens ToOffset metod. Metodens enda parameter är förskjutningen av det nya datum- och tidsvärdet som metoden returnerar.

Om till exempel datum och tid för en användarbegäran för en webbsida är känd och serialiseras som en sträng i formatet MM/dd/ååååå hh:mm:ss zzzz konverterar följande ReturnTimeOnServer metod det här datum- och tidsvärdet till datum och tid på webbservern:

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

Om metoden skickar strängen "9/1/2007 5:32:07 -05:00", som representerar datum och tid i en tidszon fem timmar tidigare än UTC, returneras "9/1/2007 3:32:07 AM -07:00" för en server som finns i U.S. Pacific Standard Time-zonen.

Klassen TimeZoneInfo innehåller också en överlagring av metoden TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) som utför tidszonskonverteringar med ToOffset(TimeSpan) värden. Metodens parametrar är ett DateTimeOffset värde och en referens till den tidszon som tiden ska konverteras till. Metodanropet returnerar ett DateTimeOffset värde. Metoden i föregående exempel kan till exempel ReturnTimeOnServer skrivas om på följande sätt för att anropa ConvertTime(DateTimeOffset, TimeZoneInfo) metoden.

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

Se även