Időzónák közötti időátalakítás

Egyre fontosabbá válik minden olyan alkalmazás számára, amely dátumokkal és időpontokkal dolgozik az időzónák közötti különbségek kezelése érdekében. Az alkalmazások már nem feltételezhetik, hogy minden alkalommal a helyi idő kifejezhető, ami a DateTime struktúrából elérhető idő. Például egy olyan weblap, amely a Egyesült Államok keleti részén jeleníti meg az aktuális időt, nem lesz hiteles a kelet-ázsiai ügyfelek számára. Ez a cikk bemutatja, hogyan alakíthatja át az időzónából a másikba az időzónákat, és hogyan alakíthat át DateTimeOffset korlátozott időzóna-tudatosságú értékeket.

Konvertálás koordinált univerzális időre

Az egyezményes világidő (UTC) egy nagy pontosságú, atomi idő szabvány. A világ időzónái az UTC pozitív vagy negatív eltolásaként vannak kifejezve. Így az UTC időzóna nélküli vagy időzóna-semleges időpontot biztosít. Az UTC használata akkor ajánlott, ha fontos a dátum és az idő hordozhatósága a számítógépek között. A dátumok és időpontok használatával kapcsolatos részletes és egyéb ajánlott eljárásokért tekintse meg a DateTime használatával kapcsolatos ajánlott eljárásokat a .NET-keretrendszer. Az egyes időzónák UTC-vé alakítása megkönnyíti az idő összehasonlítását.

Feljegyzés

Szerializálhat egy struktúrát DateTimeOffset is, amely egyértelműen egy adott időpontot jelöl. Mivel DateTimeOffset az objektumok dátum- és időértéket tárolnak az UTC-től való eltolással együtt, mindig egy adott időpontot jelölnek az UTC-hez viszonyítva.

Az idő UTC-vé alakításának legegyszerűbb módja a static (Shared Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime) metódus meghívása. A metódus által végrehajtott pontos átalakítás a paraméter Kind tulajdonságának dateTime értékétől függ, ahogy az alábbi táblázat is mutatja:

DateTime.Kind Átalakítás
DateTimeKind.Local A helyi időt UTC-vé alakítja.
DateTimeKind.Unspecified Feltételezi, hogy a dateTime paraméter helyi idő, és a helyi időt UTC-vé alakítja.
DateTimeKind.Utc A paramétert dateTime változatlanul adja vissza.

Az alábbi kód az aktuális helyi időt UTC-vé alakítja, és megjeleníti az eredményt a konzolon:

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

Ha a dátum- és időérték nem a helyi időpontot vagy az UTC-t jelöli, a ToUniversalTime metódus valószínűleg hibás eredményt ad vissza. A metódussal TimeZoneInfo.ConvertTimeToUtc azonban konvertálhatja a dátumot és az időt egy megadott időzónából. A cél időzónát képviselő objektumok beolvasásáról TimeZoneInfo további információt a helyi rendszeren definiált időzónák megkeresése című témakörben talál. A következő kód a keleti téli idő UTC-vé alakításához használja a TimeZoneInfo.ConvertTimeToUtc metódust:

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

A TimeZoneInfo.ConvertTimeToUtc metódus egy ArgumentException ha az DateTime objektum tulajdonsága Kind és az időzóna nem egyezik. Eltérés akkor fordul elő, ha a tulajdonság azDateTimeKind.Local, de az TimeZoneInfo objektum nem a helyi időzónát jelöli, vagy ha a Kind tulajdonság, DateTimeKind.Utc de az TimeZoneInfo objektum nem egyenlőTimeZoneInfo.Utc.Kind

Ezen metódusok mindegyike paraméterként veszi fel DateTime az értékeket, és visszaad egy DateTime értéket. Értékek esetén DateTimeOffset a DateTimeOffset struktúra egy ToUniversalTime példánymetódussal rendelkezik, amely az aktuális példány dátumát és idejét UTC-vé alakítja. Az alábbi példa meghívja a metódust egy ToUniversalTime helyi idő és több más időpont UTC-vé alakítására:

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   

UTC konvertálása kijelölt időzónává

Ha az UTC-t helyi idő szerint szeretné átalakítani, tekintse meg az UTC helyi idő szerintivé alakítását az alábbi szakaszban. Ha az UTC-t a kijelölt időzónában lévő időpontra szeretné konvertálni, hívja meg a metódust ConvertTimeFromUtc . A metódus két paramétert használ:

  • Az átalakítandó UTC. Ennek olyan DateTime értéknek kell lennie, amelynek Kind a tulajdonsága a következőre Unspecified van állítva: vagy Utc.

  • Az az időzóna, amelybe az UTC-t konvertálja.

A következő kód konvertálja az UTC-t a központi téli időszámításra:

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

UTC konvertálása helyi idő szerint

Ha az UTC-t helyi időpontra szeretné konvertálni, hívja meg annak az objektumnak a ToLocalTimeDateTime metódusát, amelynek az idejét át szeretné alakítani. A metódus pontos viselkedése az objektum Kind tulajdonságának értékétől függ, ahogy az alábbi táblázat is mutatja:

DateTime.Kind Átalakítás
DateTimeKind.Local DateTime Az értéket változatlanul adja vissza.
DateTimeKind.Unspecified Feltételezi, hogy az DateTime érték UTC, és az UTC-t helyi idő szerint konvertálja.
DateTimeKind.Utc DateTime Az értéket helyi időre konvertálja.

Feljegyzés

A TimeZone.ToLocalTime metódus a metódushoz DateTime.ToLocalTime hasonlóan viselkedik. A konvertáláshoz egyetlen paraméterre van szükség, amely a dátum- és időérték.

A kijelölt időzónákban lévő időt helyi idővé is konvertálhatja a static (Shared Visual Basic) TimeZoneInfo.ConvertTime metódussal. Ezt a technikát a következő szakaszban tárgyaljuk.

Konvertálás bármely két időzóna között

Az osztály két időzónája közötti konvertáláshoz használja az osztály alábbi két static (Shared Visual Basic)-metódusát TimeZoneInfo :

  • ConvertTime

    Ennek a metódusnak a paraméterei az átalakítandó dátum- és időérték, a TimeZoneInfo dátum- és időérték időzónáját jelképező objektum, valamint egy TimeZoneInfo objektum, amely az időzónát jelöli a dátum és az idő értékének konvertálásához.

  • ConvertTimeBySystemTimeZoneId

    Ennek a metódusnak a paraméterei az átalakítandó dátum- és időérték, a dátum- és időérték időzónájának azonosítója, valamint az időzóna azonosítója, a dátum- és időérték konvertálásához.

Mindkét módszer megköveteli, hogy az Kind átalakítandó dátum- és időérték tulajdonsága, valamint az TimeZoneInfo időzónáját jelképező objektum vagy időzóna-azonosító egymással azonos legyen. Ellenkező esetben egy ArgumentException dobás történik. Ha például a Kind dátum- és időérték tulajdonsága azDateTimeKind.Local, akkor a rendszer kivételt jelez, ha a TimeZoneInfo metódus paraméterként átadott objektuma nem egyenlő.TimeZoneInfo.Local A rendszer kivételt is alkalmaz, ha a metódus paraméterként átadott azonosítója nem egyenlő.TimeZoneInfo.Local.Id

Az alábbi példa a ConvertTime hawaii téli időről a helyi időszámításra való konvertálást használja:

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

DateTimeOffset-értékek konvertálása

Az objektumok által DateTimeOffset képviselt dátum- és időértékek nem teljes mértékben időzóna-tudatában vannak, mivel az objektum a példányosításkor nem kapcsolódik az időzónához. Az alkalmazásoknak azonban sok esetben egyszerűen át kell alakítaniuk egy dátumot és időt az UTC-től eltérő két eltolás alapján, nem pedig az adott időzónákban. Az átalakítás végrehajtásához meghívhatja az aktuális példány metódusát ToOffset . A metódus egyetlen paramétere a metódus által visszaadott új dátum- és időérték eltolása.

Ha például egy weblapra vonatkozó felhasználói kérelem dátuma és időpontja ismert, és sztringként van szerializálva MM/dd/yyy hh:mm:ss zzzz formátumban, a következő ReturnTimeOnServer metódus ezt a dátum- és időértéket a webkiszolgálón lévő dátummá és idővé alakítja:

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

Ha a metódus átadja a "2007.09.01.05:32:07 -05:00" sztringet, amely egy időzónában az UTC-nél öt órával korábbi dátumot és időt jelöli, a "2007.09.01. 03:32:07 -07:00" értéket adja vissza az Egyesült Államok csendes-óceáni standard időzónájában található kiszolgáló esetében.

Az TimeZoneInfo osztály magában foglalja a TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) metódus túlterhelését is, amely időzóna-átalakításokat hajt végre értékekkel ToOffset(TimeSpan) . A metódus paraméterei egy DateTimeOffset érték és egy hivatkozás arra az időzónára, amelyre az időt konvertálni kell. A metódushívás egy DateTimeOffset értéket ad vissza. Az előző példában szereplő metódus például ReturnTimeOnServer a következőképpen írható át a ConvertTime(DateTimeOffset, TimeZoneInfo) metódus meghívásához.

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

Lásd még