Převádění časů mezi časovými pásmy
Je stále důležitější pro každou aplikaci, která pracuje s daty a časy, aby zvládla rozdíly mezi časovými pásmy. Aplikace již nemůže předpokládat, že všechny časy mohou být vyjádřeny v místním čase, což je čas dostupný ze DateTime struktury. Například webová stránka, která zobrazuje aktuální čas ve východní části USA nebude mít důvěryhodnost zákazníka ve východní Asii. Tento článek vysvětluje, jak převést časy z jednoho časového pásma na jiné a převést DateTimeOffset hodnoty, které mají omezené povědomí o časovém pásmu.
Převod na koordinovaný univerzální čas
Koordinovaný univerzální čas (UTC) je standard s vysokou přesností a atomovým časem. Časová pásma světa jsou vyjádřena jako kladné nebo záporné posuny od UTC. UTC proto poskytuje časovou zónu volného času nebo neutrálního časového pásma. Použití standardu UTC se doporučuje, pokud je důležitá přenositelnost data a času mezi počítači. Podrobnosti a další osvědčené postupy při používání kalendářních dat a časů najdete v tématu Kódování osvědčených postupů pomocí dateTime v rozhraní .NET Framework. Převod jednotlivých časových pásem na UTC usnadňuje porovnání času.
Poznámka:
Můžete také serializovat DateTimeOffset strukturu tak, aby představovala jeden bod v čase jednoznačně. Vzhledem k tomu, že DateTimeOffset objekty ukládají hodnotu data a času spolu s posunem od času UTC, vždy představují konkrétní bod v čase vzhledem k času UTC.
Nejjednodušší způsob, jak převést čas na UTC, je volání static
metody (Shared
v jazyce Visual Basic). TimeZoneInfo.ConvertTimeToUtc(DateTime) Přesný převod provedený metodou závisí na hodnotě dateTime
vlastnosti parametru Kind , jak ukazuje následující tabulka:
DateTime.Kind |
Převod |
---|---|
DateTimeKind.Local |
Převede místní čas na UTC. |
DateTimeKind.Unspecified |
Předpokládá, že dateTime parametr je místní čas a převede místní čas na UTC. |
DateTimeKind.Utc |
dateTime Vrátí parametr beze změny. |
Následující kód převede aktuální místní čas na UTC a zobrazí výsledek do konzoly:
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))
Pokud hodnota data a času nepředstavuje místní čas nebo UTC, ToUniversalTime metoda pravděpodobně vrátí chybný výsledek. Pomocí metody však můžete TimeZoneInfo.ConvertTimeToUtc převést datum a čas ze zadaného časového pásma. Podrobnosti o načtení objektu TimeZoneInfo , který představuje cílové časové pásmo, naleznete v tématu Vyhledání časových pásem definovaných v místním systému. Následující kód používá metodu k převodu východního standardního TimeZoneInfo.ConvertTimeToUtc času 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 vyvolá chybu ArgumentException , pokud je vlastnost objektu DateTimeKind a časové pásmo neodpovídají. Neshoda nastane, Kind pokud je DateTimeKind.Local vlastnost, ale TimeZoneInfo objekt nepředstavuje místní časové pásmo, nebo pokud Kind je DateTimeKind.Utc vlastnost, ale TimeZoneInfo objekt se nerovná TimeZoneInfo.Utc.
Všechny tyto metody přebírají DateTime hodnoty jako parametry a vracejí DateTime hodnotu. Pro DateTimeOffset hodnoty DateTimeOffset má struktura metodu ToUniversalTime instance, která převede datum a čas aktuální instance na UTC. Následující příklad volá metodu ToUniversalTime pro převod místního času a několikrát jindy 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
Převod UTC na určené časové pásmo
Pokud chcete převést UTC na místní čas, přečtěte si část Převod UTC na místní čas , která následuje. Pokud chcete převést utc na čas v libovolném časovém pásmu, které určíte, zavolejte metodu ConvertTimeFromUtc . Metoda má dva parametry:
Utc, který chcete převést. Musí to být DateTime hodnota, jejíž Kind vlastnost je nastavena na
Unspecified
neboUtc
.Časové pásmo, na které se má čas UTC převést.
Následující kód převede UTC na standardní čas (UTC):
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
Převod času UTC na místní čas
Chcete-li převést UTC na místní čas, zavolejte ToLocalTime metodu objektu DateTime , jehož čas chcete převést. Přesné chování metody závisí na hodnotě vlastnosti objektu Kind , jak ukazuje následující tabulka:
DateTime.Kind |
Převod |
---|---|
DateTimeKind.Local |
DateTime Vrátí hodnotu beze změny. |
DateTimeKind.Unspecified |
Předpokládá, že DateTime hodnota je UTC a převede utc na místní čas. |
DateTimeKind.Utc |
DateTime Převede hodnotu na místní čas. |
Poznámka:
Metoda TimeZone.ToLocalTime se chová stejně jako DateTime.ToLocalTime
metoda. Převod trvá jeden parametr, což je hodnota data a času.
Pomocí metody (Shared
v jazyce Visual Basic) TimeZoneInfo.ConvertTime můžete také převést čas v libovolném určeném časovém pásmu na místní čas static
. Tato technika je popsána v další části.
Převod mezi dvěma časovými pásmy
Mezi libovolnými dvěma časovými pásmy můžete převést některou z následujících dvou static
metod TimeZoneInfo (Shared
v jazyce Visual Basic) třídy:
-
Parametry této metody jsou hodnota data a času, která se má převést,
TimeZoneInfo
objekt, který představuje časové pásmo hodnoty data a času, aTimeZoneInfo
objekt, který představuje časové pásmo pro převod hodnoty data a času na. -
Parametry této metody jsou hodnota data a času, která se má převést, identifikátor časového pásma hodnoty data a času a identifikátor časového pásma pro převod hodnoty data a času na.
Obě metody vyžadují, aby Kind vlastnost hodnoty data a času převeďte a identifikátor objektu TimeZoneInfo nebo časového pásma, který představuje jeho časové pásmo, vzájemně odpovídá. ArgumentException V opačném případě je vyvolán. Pokud je například Kind
vlastnost hodnoty DateTimeKind.Local
data a času , je vyvolán výjimka, pokud TimeZoneInfo
objekt předán jako parametr metodě není rovna TimeZoneInfo.Local
. Výjimka se vyvolá také v případě, že identifikátor předaný jako parametr metodě není rovna TimeZoneInfo.Local.Id
.
Následující příklad používá metodu ConvertTime pro převod z havajského standardního času na místní čas:
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
Převod hodnot DateTimeOffset
Hodnoty data a času reprezentované DateTimeOffset objekty nejsou plně v časovém pásmu, protože objekt je oddělený od časového pásma v okamžiku vytvoření instance. V mnoha případech ale aplikace potřebuje jednoduše převést datum a čas na základě dvou různých posunů oproti času UTC, nikoli podle času v konkrétních časových pásmech. Chcete-li provést tento převod, můžete volat metodu ToOffset aktuální instance. Jediný parametr metody je posun hodnoty nového data a času, kterou metoda vrátí.
Pokud je například známo datum a čas požadavku uživatele na webovou stránku a je serializován jako řetězec ve formátu MM/dd/rrrr hh:mm:ss zzzz, následující ReturnTimeOnServer
metoda převede tuto hodnotu data a času na datum a čas na webovém serveru:
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
Pokud metoda předá řetězec "9/1/2007 5:32:07 -05:00", který představuje datum a čas v časovém pásmu pět hodin dříve než UTC, vrátí "9/1/2007 3:32:07 AM -07:00" pro server umístěný v americkém standardním časovém pásmu.
Třída TimeZoneInfo také obsahuje přetížení TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) metody, která provádí převody časových pásem s ToOffset(TimeSpan) hodnotami. Parametry metody jsou DateTimeOffset hodnota a odkaz na časové pásmo, na které se má čas převést. Volání metody vrátí DateTimeOffset hodnotu. Například metodu ReturnTimeOnServer
v předchozím příkladu lze přepsat následujícím způsobem, aby volala metodu 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