Sdílet prostřednictvím


Volba mezi DateTime, DateOnly, DateTimeOffset, TimeSpan, TimeOnly a TimeZoneInfo

Aplikace .NET můžou informace o datu a čase používat několika způsoby. Mezi nejběžnější způsoby použití informací o datu a čase patří:

  • Pokud chcete odrážet pouze datum, aby informace o čase nebyly důležité.
  • Chcete-li odrážet pouze čas, aby informace o datu nebyly důležité.
  • Aby se projevilo abstraktní datum a čas, které nejsou svázané s konkrétním časem a místem (například většina obchodů v mezinárodním řetězci otevírá ve všední dny v 9:00).
  • Pokud chcete načíst informace o datu a čase ze zdrojů mimo .NET, obvykle tam, kde jsou informace o datu a čase uložené v jednoduchém datovém typu.
  • Jedinečně a jednoznačně identifikovat jeden bod v čase. Některé aplikace vyžadují, aby datum a čas byly jednoznačné pouze v hostitelském systému. Jiné aplikace vyžadují, aby byl jednoznačný v systémech (tj. datum serializované v jednom systému může být smysluplně deserializováno a používáno v jiném systému kdekoli na světě).
  • Chcete-li zachovat více souvisejících časů (například místní čas žadatele a čas přijetí webového požadavku serveru).
  • Chcete-li provést aritmetické operace s datem a časem, s výsledkem, který jednoznačně identifikuje jednoznačně určený časový okamžik.

.NET obsahuje typy DateTime, DateOnly, DateTimeOffset, TimeSpan, TimeOnlya TimeZoneInfo, z nichž všechny se dají použít k vytváření aplikací, které pracují s daty a časy.

Poznámka

Tento článek se nezabývá TimeZone, protože jeho funkcionalita je téměř zcela začleněna do třídy TimeZoneInfo. Kdykoli je to možné, použijte místo třídy TimeZoneInfo třídu TimeZone.

DateTimeOffset – struktura

Struktura DateTimeOffset představuje hodnotu data a času společně s posunem, který označuje, kolik se tato hodnota liší od času UTC. Proto hodnota vždy jednoznačně identifikuje jeden bod v čase.

Typ DateTimeOffset zahrnuje všechny funkce typu DateTime spolu s povědomím o časovém pásmu. To je vhodné pro aplikace, které:

  • Jedinečně a jednoznačně identifikujte jeden bod v čase. Typ DateTimeOffset lze použít k jednoznačnému definování významu "nyní", k protokolování časů transakcí, k protokolování časů událostí systému nebo aplikace a k zaznamenávání časů vytváření a úprav souborů.
  • Proveďte obecné aritmetické operace s daty a časem.
  • Zachovávejte více souvisejících časů, pokud jsou tyto časy uloženy jako dvě samostatné hodnoty nebo jako dva členy struktury.

Poznámka

Tato použití pro DateTimeOffset hodnoty jsou mnohem častější než hodnoty DateTime. Proto zvažte DateTimeOffset jako výchozí typ data a času pro vývoj aplikací.

Hodnota DateTimeOffset není svázaná s určitým časovým pásmem, ale může pocházet z různých časových pásem. Následující příklad obsahuje seznam časových pásem, do kterých může patřit několik DateTimeOffset hodnot (včetně místního pacifického standardního času).

using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;

      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;

      Console.WriteLine("{0} could belong to the following time zones:",
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();
      // Iterate time zones
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   }
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa
Imports System.Collections.ObjectModel

Module TimeOffsets
    Public Sub Main()
        Dim thisTime As DateTimeOffset

        thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
        ShowPossibleTimeZones(thisTime)

        thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))
        ShowPossibleTimeZones(thisTime)

        thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
        ShowPossibleTimeZones(thisTime)
    End Sub

    Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
        Dim offset As TimeSpan = offsetTime.Offset
        Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

        Console.WriteLine("{0} could belong to the following time zones:", _
                          offsetTime.ToString())
        ' Get all time zones defined on local system
        timeZones = TimeZoneInfo.GetSystemTimeZones()
        ' Iterate time zones
        For Each timeZone As TimeZoneInfo In timeZones
            ' Compare offset with offset for that date in that time zone
            If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
                Console.WriteLine("   {0}", timeZone.DisplayName)
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' This example displays the following output to the console:
'       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
'          (GMT-07:00) Arizona
'          (GMT-08:00) Pacific Time (US & Canada)
'          (GMT-08:00) Tijuana, Baja California
'       
'       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
'          (GMT-06:00) Central America
'          (GMT-06:00) Central Time (US & Canada)
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
'          (GMT-06:00) Saskatchewan
'       
'       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
'          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
'          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
'          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
'          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
'          (GMT+01:00) West Central Africa

Výstup ukazuje, že každá hodnota data a času v tomto příkladu může patřit alespoň do tří různých časových pásem. Hodnota DateTimeOffset 10. 6. 2007 ukazuje, že pokud hodnota data a času představuje letní čas, jeho posun od UTC nemusí nutně odpovídat základnímu posunu UTC původního časového pásma nebo posunu od UTC uvedenému v jeho zobrazovaném názvu. Vzhledem k tomu, že jedna hodnota DateTimeOffset není úzce spojená s časovým pásmem, nemůže odrážet přechod časového pásma do a z letního času. To může být problematické, když se k manipulaci s DateTimeOffset hodnotou používá aritmetika data a času. Diskuzi o tom, jak provádět aritmetické operace s daty a časy způsobem, který bere v úvahu pravidla úpravy časového pásma, viz část Provádění aritmetických operací s daty a časy.

Struktura DateTime

Hodnota DateTime definuje konkrétní datum a čas. Obsahuje vlastnost Kind, která poskytuje omezené informace o časovém pásmu, do kterého toto datum a čas patří. Hodnota DateTimeKind vrácená vlastností Kind označuje, zda hodnota DateTime představuje místní čas (DateTimeKind.Local), koordinovaný univerzální čas (UTC) (DateTimeKind.Utc) nebo nezadanou dobu (DateTimeKind.Unspecified).

Struktura DateTime je vhodná pro aplikace s jednou nebo více z následujících charakteristik:

  • Práce s abstraktními daty a časy
  • Práce s daty a časy, u kterých chybí informace o časovém pásmu
  • Pracovat pouze s daty a časy UTC.
  • Provádějte aritmetiku s daty a časem, ale zaměřuje se na obecné výsledky. Například v operaci sčítání, která přidává šest měsíců k určitému datu a času, není často důležité, zda je výsledek upraven pro letní čas.

Pokud konkrétní DateTime hodnota nepředstavuje UTC, je tato hodnota data a času často nejednoznačná nebo omezená ve své přenositelnosti. Pokud například hodnota DateTime představuje místní čas, je přenosná v rámci tohoto místního časového pásma (to znamená, že pokud je hodnota deserializována v jiném systému ve stejném časovém pásmu, tato hodnota stále jednoznačně identifikuje jeden bod v čase). Mimo místní časové pásmo může mít hodnota DateTime více interpretací. Pokud je vlastnost Kind hodnoty DateTimeKind.Unspecified, je ještě méně přenosná: nyní je nejednoznačná ve stejném časovém pásmu a možná i ve stejném systému, kde byla poprvé serializována. Pouze pokud DateTime hodnota představuje UTC, tato hodnota jednoznačně identifikuje jeden bod v čase bez ohledu na systém nebo časové pásmo, ve kterém se hodnota používá.

Důležitý

Při ukládání nebo sdílení dat DateTime použijte UTC a nastavte vlastnost DateTime hodnoty Kind na DateTimeKind.Utc.

DateOnly – struktura

Struktura DateOnly představuje konkrétní datum bez času. Vzhledem k tomu, že nemá žádnou časovou komponentu, představuje datum od začátku dne do konce dne. Tato struktura je ideální pro ukládání konkrétních kalendářních dat, jako jsou datum narození, datum výročí, svátek nebo datum související s podnikáním.

I když byste mohli použít DateTime a současně ignorovat časovou komponentu, existuje několik výhod použití DateOnly přes DateTime:

  • Struktura DateTime se může přesunout do předchozího nebo následujícího dne, pokud je ovlivněna časovým pásmem. DateOnly nelze posunovat časovým pásmem a vždy představuje nastavené datum.
  • Serializace struktury DateTime zahrnuje časovou komponentu, která může překrývat záměr dat. DateOnly také serializuje méně dat.
  • Když kód komunikuje s databází, jako je SQL Server, jsou celá data obecně uložena jako datový typ date, což nezahrnuje čas. DateOnly lépe odpovídá typu databáze.

Další informace o DateOnlynaleznete v tématu Jak používat struktury DateOnly a TimeOnly.

Důležitý

DateOnly není k dispozici pro rozhraní .NET Framework.

Struktura TimeSpan

Struktura TimeSpan představuje časový interval. Mezi její dvě typické použití patří:

  • Odráží časový interval mezi dvěma hodnotami data a času. Například odečtení jedné DateTime hodnoty z jiné vrátí hodnotu TimeSpan.
  • Měření uplynulé doby. Například vlastnost Stopwatch.Elapsed vrátí hodnotu TimeSpan, která odráží časový interval, který uplynul od volání jedné z Stopwatch metod, které začínají měřit uplynulý čas.

Hodnotu TimeSpan lze také použít jako náhradu za hodnotu DateTime, pokud tato hodnota odráží čas bez odkazu na konkrétní den. Toto použití se podobá vlastnostem DateTime.TimeOfDay a DateTimeOffset.TimeOfDay, která vrací hodnotu TimeSpan, která představuje čas bez odkazu na datum. Například TimeSpan strukturu lze použít k vyjádření denního otevření nebo uzavření obchodu, nebo lze použít k vyjádření času, kdy dojde k jakékoli běžné události.

Následující příklad definuje StoreInfo strukturu, která zahrnuje TimeSpan objekty pro otevření a uzavření úložiště, stejně jako TimeZoneInfo objekt, který představuje časové pásmo úložiště. Struktura obsahuje také dvě metody, IsOpenNow a IsOpenAt, které indikují, jestli je úložiště otevřené v době určené uživatelem, který se předpokládá, že je v místním časovém pásmu.

using System;

public struct StoreInfo
{
   public String store;
   public TimeZoneInfo tz;
   public TimeSpan open;
   public TimeSpan close;

   public bool IsOpenNow()
   {
      return IsOpenAt(DateTime.Now.TimeOfDay);
   }

   public bool IsOpenAt(TimeSpan time)
   {
      TimeZoneInfo local = TimeZoneInfo.Local;
      TimeSpan offset = TimeZoneInfo.Local.BaseUtcOffset;

      // Is the store in the same time zone?
      if (tz.Equals(local)) {
         return time >= open & time <= close;
      }
      else {
         TimeSpan delta = TimeSpan.Zero;
         TimeSpan storeDelta = TimeSpan.Zero;

         // Is it daylight saving time in either time zone?
         if (local.IsDaylightSavingTime(DateTime.Now.Date + time))
            delta = local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1].DaylightDelta;

         if (tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(DateTime.Now.Date + time, local, tz)))
            storeDelta = tz.GetAdjustmentRules()[tz.GetAdjustmentRules().Length - 1].DaylightDelta;

         TimeSpan comparisonTime = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate();
         return comparisonTime >= open && comparisonTime <= close;
      }
   }
}
Public Structure StoreInfo
    Dim store As String
    Dim tz As TimeZoneInfo
    Dim open As TimeSpan
    Dim close As TimeSpan

    Public Function IsOpenNow() As Boolean
        Return IsOpenAt(Date.Now.TimeOfDay)
    End Function

    Public Function IsOpenAt(time As TimeSpan) As Boolean
        Dim local As TimeZoneInfo = TimeZoneInfo.Local
        Dim offset As TimeSpan = TimeZoneInfo.Local.BaseUtcOffset

        ' Is the store in the same time zone?
        If tz.Equals(local) Then
            Return time >= open AndAlso time <= close
        Else
            Dim delta As TimeSpan = TimeSpan.Zero
            Dim storeDelta As TimeSpan = TimeSpan.Zero

            ' Is it daylight saving time in either time zone?
            If local.IsDaylightSavingTime(Date.Now.Date + time) Then
                delta = local.GetAdjustmentRules(local.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            If tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(Date.Now.Date + time, local, tz))
                storeDelta = tz.GetAdjustmentRules(tz.GetAdjustmentRules().Length - 1).DaylightDelta
            End If
            Dim comparisonTime As TimeSpan = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate
            Return (comparisonTime >= open AndAlso comparisonTime <= close)
        End If
    End Function
End Structure

Strukturu StoreInfo pak může použít klientský kód podobný následujícímu.

public class Example
{
   public static void Main()
   {
      // Instantiate a StoreInfo object.
      var store103 = new StoreInfo();
      store103.store = "Store #103";
      store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
      // Store opens at 8:00.
      store103.open = new TimeSpan(8, 0, 0);
      // Store closes at 9:30.
      store103.close = new TimeSpan(21, 30, 0);

      Console.WriteLine("Store is open now at {0}: {1}",
                        DateTime.Now.TimeOfDay, store103.IsOpenNow());
      TimeSpan[] times = { new TimeSpan(8, 0, 0), new TimeSpan(21, 0, 0),
                           new TimeSpan(4, 59, 0), new TimeSpan(18, 31, 0) };
      foreach (var time in times)
         Console.WriteLine("Store is open at {0}: {1}",
                           time, store103.IsOpenAt(time));
   }
}
// The example displays the following output:
//       Store is open now at 15:29:01.6129911: True
//       Store is open at 08:00:00: True
//       Store is open at 21:00:00: True
//       Store is open at 04:59:00: False
//       Store is open at 18:31:00: True
Module Example
    Public Sub Main()
        ' Instantiate a StoreInfo object.
        Dim store103 As New StoreInfo()
        store103.store = "Store #103"
        store103.tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
        ' Store opens at 8:00.
        store103.open = new TimeSpan(8, 0, 0)
        ' Store closes at 9:30.
        store103.close = new TimeSpan(21, 30, 0)

        Console.WriteLine("Store is open now at {0}: {1}",
                          Date.Now.TimeOfDay, store103.IsOpenNow())
        Dim times() As TimeSpan = {New TimeSpan(8, 0, 0),
                                    New TimeSpan(21, 0, 0),
                                    New TimeSpan(4, 59, 0),
                                    New TimeSpan(18, 31, 0)}
        For Each time In times
            Console.WriteLine("Store is open at {0}: {1}",
                              time, store103.IsOpenAt(time))
        Next
    End Sub
End Module
' The example displays the following output:
'       Store is open now at 15:29:01.6129911: True
'       Store is open at 08:00:00: True
'       Store is open at 21:00:00: False
'       Store is open at 04:59:00: False
'       Store is open at 18:31:00: False

TimeOnly – struktura

Struktura TimeOnly představuje hodnotu času, například denní budík nebo v kolik hodin každý den obědváte. TimeOnly je omezena na rozsah 00:00:00.0000000 - 23:59:59,99999999999, konkrétní denní čas.

Před zavedením typu TimeOnly programátoři obvykle používali typ DateTime nebo typ TimeSpan, který představuje určitý čas. Použití těchto struktur k simulaci času bez data však může představovat některé problémy, které TimeOnly řeší:

  • TimeSpan představuje uplynulý čas, například čas měřený pomocí stopek. Horní rozsah je více než 29 000 let a jeho hodnota může být záporná, což označuje pohyb zpět v čase. Záporná TimeSpan nezoznačuje konkrétní čas dne.
  • Pokud se TimeSpan používá jako čas dne, existuje riziko, že může být změněno na hodnotu mimo 24 hodinové období. TimeOnly toto riziko nemá. Pokud například pracovní směna zaměstnance začíná v 18:00 a trvá 8 hodin, přidání 8 hodin do struktury TimeOnly přechází na 2:00.
  • Použití DateTime pro čas během dne vyžaduje, aby bylo k času přidruženo libovolné datum, které se pak později ignoruje. Je běžné zvolit DateTime.MinValue (0001-01-01-01) jako datum, ale pokud jsou hodiny odečteny od hodnoty DateTime, může dojít k OutOfRange výjimce. TimeOnly tento problém nemá, protože se čas posunuje dopředu a dozadu kolem 24hodinového časového rámce.
  • Serializace struktury DateTime zahrnuje komponentu data, která může překrývat záměr dat. TimeOnly také serializuje méně dat.

Další informace o TimeOnlynaleznete v tématu Jak používat struktury DateOnly a TimeOnly.

Důležitý

TimeOnly není k dispozici pro rozhraní .NET Framework.

třída TimeZoneInfo

Třída TimeZoneInfo představuje libovolné časové pásmo Země a umožňuje převod libovolného data a času v jednom časovém pásmu na ekvivalent v jiném časovém pásmu. Třída TimeZoneInfo umožňuje pracovat s kalendářními daty a časy, aby jakákoli hodnota data a času jednoznačně identifikovala jeden bod v čase. Třída TimeZoneInfo je také rozšiřitelná. I když závisí na informacích o časovém pásmu poskytovaných pro systémy Windows a definovaných v registru, podporuje vytváření vlastních časových pásem. Podporuje také serializaci a deserializaci informací o časovém pásmu.

V některých případech může plné využití třídy TimeZoneInfo vyžadovat další vývojovou práci. Pokud hodnoty data a času nejsou úzce svázané s časovými pásmy, do kterých patří, vyžaduje se další práce. Pokud vaše aplikace neposkytuje nějaký mechanismus pro propojení data a času s přidruženým časovým pásmem, je snadné zrušit přidružení konkrétní hodnoty data a času od časového pásma. Jednou z metod propojení těchto informací je definovat třídu nebo strukturu, která obsahuje hodnotu data i času a přidružený objekt časového pásma.

Chcete-li využít podporu časového pásma v rozhraní .NET, musíte znát časové pásmo, do kterého patří hodnota data a času při vytvoření instance tohoto objektu data a času. Časové pásmo není často známo, zejména ve webových nebo síťových aplikacích.

Viz také