Delen via


Kiezen tussen DateTime, DateOnly, DateTimeOffset, TimeSpan, TimeOnly en TimeZoneInfo

.NET-toepassingen kunnen op verschillende manieren datum- en tijdgegevens gebruiken. De meest voorkomende toepassingen van datum- en tijdgegevens zijn:

  • Als u alleen een datum wilt weergeven, zodat tijdgegevens niet belangrijk zijn.
  • Als u alleen een tijd wilt weergeven, zodat datumgegevens niet belangrijk zijn.
  • Om een abstracte datum en tijd weer te geven die niet is gekoppeld aan een specifieke tijd en plaats (bijvoorbeeld de meeste winkels in een internationale keten zijn geopend op weekdagen om 9:00 uur).
  • Voor het ophalen van datum- en tijdgegevens uit bronnen buiten .NET, meestal waar datum- en tijdgegevens worden opgeslagen in een eenvoudig gegevenstype.
  • Om uniek en ondubbelzinnig een single point in time te identificeren. Voor sommige toepassingen is vereist dat een datum en tijd alleen ondubbelzinnig zijn op het hostsysteem. Andere apps vereisen dat het eenduidig is tussen systemen (dat wil zeggen dat een datum die op het ene systeem is geserialiseerd, zinvol kan worden gedeserialiseerd en op een ander systeem overal ter wereld kan worden gebruikt).
  • Als u meerdere gerelateerde tijden wilt behouden (zoals de lokale tijd van de aanvrager en de tijd van ontvangst van een webaanvraag).
  • Om rekenkundige datum- en tijdberekeningen uit te voeren, mogelijk met een resultaat dat uniek en ondubbelzinnig één bepaald tijdstip identificeert.

.NET bevat de DateTimetypen , , DateOnlyDateTimeOffset, TimeOnlyTimeSpanen TimeZoneInfo typen, die allemaal kunnen worden gebruikt om toepassingen te bouwen die werken met datums en tijden.

Notitie

In dit artikel wordt niet besproken TimeZone omdat de functionaliteit ervan bijna volledig is opgenomen in de TimeZoneInfo klasse. Gebruik indien mogelijk de TimeZoneInfo klasse in plaats van de TimeZone klasse.

De structuur DateTimeOffset

De DateTimeOffset structuur vertegenwoordigt een datum- en tijdwaarde, samen met een offset die aangeeft hoeveel die waarde verschilt van UTC. De waarde identificeert dus altijd ondubbelzinnig een enkel punt in de tijd.

Het DateTimeOffset type bevat alle functionaliteit van het DateTime type, samen met tijdzonebewustzijn. Dit maakt het geschikt voor toepassingen die:

  • Uniek en ondubbelzinnig een single point in time identificeren. Het DateTimeOffset type kan worden gebruikt om ondubbelzinnig de betekenis van 'nu' te definiëren, om transactietijden te registreren, de tijden van systeem- of toepassingsevenementen te registreren, en het maken en wijzigen van bestanden vast te leggen.
  • Algemene datum- en tijdberekeningen uitvoeren.
  • Bewaar meerdere gerelateerde tijden, zolang deze tijden worden opgeslagen als twee afzonderlijke waarden of als twee leden van een structuur.

Notitie

Deze toepassingen voor DateTimeOffset waarden komen veel vaker voor dan voor DateTime waarden. Als gevolg hiervan kunt u overwegen DateTimeOffset als het standaardtype datum en tijd voor het ontwikkelen van toepassingen.

Een DateTimeOffset waarde is niet gekoppeld aan een bepaalde tijdzone, maar kan afkomstig zijn van verschillende tijdzones. In het volgende voorbeeld ziet u de tijdzones waartoe een aantal DateTimeOffset waarden (inclusief een lokale Pacific Standard Time) behoren.

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

In de uitvoer ziet u dat elke datum- en tijdwaarde in dit voorbeeld tot ten minste drie verschillende tijdzones kan behoren. De DateTimeOffset waarde van 10-6-2007 geeft aan dat als een datum- en tijdwaarde een zomertijd vertegenwoordigt, de offset van UTC niet noodzakelijkerwijs overeenkomt met de basis-UTC-offset van de oorspronkelijke tijdzone of de offset van UTC die in de weergavenaam is gevonden. Omdat één DateTimeOffset waarde niet nauw is gekoppeld aan de tijdzone, kan deze de overgang van een tijdzone naar en van zomertijd niet weerspiegelen. Dit kan problematisch zijn wanneer rekenkundige datum en tijd wordt gebruikt om een DateTimeOffset waarde te bewerken. Zie Rekenkundige bewerkingen uitvoeren met datums en tijden voor een discussie over het uitvoeren van berekeningen op een manier die rekening houdt met de aanpassingsregels van een tijdzone.

De structuur Datum/tijd

Een DateTime waarde definieert een bepaalde datum en tijd. Het bevat een Kind eigenschap die beperkte informatie biedt over de tijdzone waartoe die datum en tijd behoort. De DateTimeKind waarde die door de Kind eigenschap wordt geretourneerd, geeft aan of de DateTime waarde de lokale tijd (DateTimeKind.Local), Coordinated Universal Time (UTC) (DateTimeKind.Utc) of een niet-opgegeven tijd (DateTimeKind.Unspecified) vertegenwoordigt.

De DateTime structuur is geschikt voor toepassingen met een of meer van de volgende kenmerken:

  • Werken met abstracte datums en tijden.
  • Werk met datums en tijden waarvoor tijdzonegegevens ontbreken.
  • Werk alleen met UTC-datums en -tijden.
  • Rekenkundige datum- en tijdbewerkingen uitvoeren, maar hebben betrekking op algemene resultaten. Bij een optellingsbewerking die zes maanden toevoegt aan een bepaalde datum en tijd, is het vaak niet belangrijk of het resultaat wordt aangepast voor zomertijd.

Tenzij een bepaalde DateTime waarde UTC vertegenwoordigt, is die datum- en tijdwaarde vaak dubbelzinnig of beperkt in de draagbaarheid. Als een DateTime waarde bijvoorbeeld de lokale tijd vertegenwoordigt, is deze draagbaar binnen die lokale tijdzone (dat wil gezegd, als de waarde wordt gedeserialiseerd op een ander systeem in dezelfde tijdzone, wordt die waarde nog steeds ondubbelzinnig aangeduid als één bepaald tijdstip). Buiten de lokale tijdzone kan die DateTime waarde meerdere interpretaties hebben. Als de eigenschap van Kind de waarde is, is DateTimeKind.Unspecifieddeze nog minder draagbaar: het is nu dubbelzinnig binnen dezelfde tijdzone en mogelijk zelfs op hetzelfde systeem waar het voor het eerst werd geserialiseerd. Alleen als een DateTime waarde UTC vertegenwoordigt, identificeert die waarde ondubbelzinnig een enkel tijdstip, ongeacht het systeem of de tijdzone waarin de waarde wordt gebruikt.

Belangrijk

Wanneer u gegevens opslaat of deeltDateTime, gebruikt u UTC en stelt u de eigenschap van Kind de DateTime waarde in op DateTimeKind.Utc.

De DateOnly-structuur

De DateOnly structuur vertegenwoordigt een specifieke datum, zonder tijd. Omdat het geen tijdcomponent heeft, vertegenwoordigt het een datum vanaf het begin van de dag tot het einde van de dag. Deze structuur is ideaal voor het opslaan van specifieke datums, zoals een geboortedatum, een jubileumdatum, een feestdag of een zakelijke datum.

Hoewel u het tijdonderdeel kunt negeren DateTime , zijn er enkele voordelen voor het gebruik DateOnlyDateTimevan:

  • De DateTime structuur kan in de vorige of volgende dag worden geïmplementeerd als deze wordt verschoven door een tijdzone. DateOnly kan niet worden verschoven door een tijdzone en vertegenwoordigt altijd de datum die is ingesteld.
  • Het serialiseren van een DateTime structuur omvat het tijdonderdeel, waardoor de intentie van de gegevens mogelijk wordt verborgen. DateOnly Serialiseert ook minder gegevens.
  • Wanneer code communiceert met een database, zoals SQL Server, worden hele datums meestal opgeslagen als het date gegevenstype, dat geen tijd bevat. DateOnly komt beter overeen met het databasetype.

Zie De structuren DateOnly en TimeOnly gebruiken voor meer informatie.DateOnly

Belangrijk

DateOnly is niet beschikbaar in .NET Framework.

De structuur Tijdspanne

De TimeSpan structuur vertegenwoordigt een tijdsinterval. De twee typische toepassingen zijn:

  • Het tijdsinterval tussen twee datum- en tijdwaarden weergeven. Als u bijvoorbeeld de ene DateTime waarde van een andere waarde aftrekken, wordt een TimeSpan waarde geretourneerd.
  • Verstreken tijd meten. De Stopwatch.Elapsed eigenschap retourneert bijvoorbeeld een TimeSpan waarde die overeenkomt met het tijdsinterval dat is verstreken sinds de aanroep van een van de Stopwatch methoden die beginnen met het meten van de verstreken tijd.

Een TimeSpan waarde kan ook worden gebruikt als vervanging voor een DateTime waarde wanneer die waarde een tijd weerspiegelt zonder verwijzing naar een bepaalde dag. Dit gebruik is vergelijkbaar met de DateTime.TimeOfDay en DateTimeOffset.TimeOfDay eigenschappen, die een TimeSpan waarde retourneren die de tijd aangeeft zonder te verwijzen naar een datum. De structuur kan bijvoorbeeld worden gebruikt om de TimeSpan dagelijkse openings- of sluitingstijd van een winkel weer te geven, of kan worden gebruikt om het tijdstip aan te geven waarop een gewone gebeurtenis plaatsvindt.

In het volgende voorbeeld wordt een StoreInfo structuur gedefinieerd die objecten bevat TimeSpan voor het openen en sluiten van winkels, evenals een TimeZoneInfo object dat de tijdzone van de winkel vertegenwoordigt. De structuur bevat ook twee methoden en IsOpenNowIsOpenAt, die aangeeft of de winkel is geopend op een tijdstip dat is opgegeven door de gebruiker, die wordt verondersteld zich in de lokale tijdzone te bevinden.

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

De StoreInfo structuur kan vervolgens worden gebruikt door clientcode zoals hieronder.

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: False
//       Store is open at 04:59:00: False
//       Store is open at 18:31:00: False
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

De TimeOnly-structuur

De TimeOnly structuur vertegenwoordigt een tijd-van-dag-waarde, zoals een dagelijkse wekker of hoe laat u elke dag luncht. TimeOnlyis beperkt tot het bereik van 00:00:00.0000000 - 23:59:59.999999999, een specifiek tijdstip van de dag.

Voordat het TimeOnly type werd geïntroduceerd, gebruikten programmeurs meestal het DateTime type of het TimeSpan type om een specifieke tijd aan te geven. Het gebruik van deze structuren om een tijd zonder datum te simuleren, kan echter enkele problemen veroorzaken, waardoor TimeOnly het volgende wordt opgelost:

  • TimeSpan vertegenwoordigt verstreken tijd, zoals de tijd die wordt gemeten met een stopwatch. Het bovenste bereik is meer dan 29.000 jaar en de waarde ervan kan negatief zijn om achteruit te gaan in de tijd. Een negatief TimeSpan geeft geen specifiek tijdstip van de dag aan.
  • Als TimeSpan wordt gebruikt als een tijdstip van de dag, is er een risico dat het kan worden gemanipuleerd naar een waarde buiten de 24-uurs dag. TimeOnly heeft dit risico niet. Als de werkdienst van een werknemer bijvoorbeeld begint om 18:00 uur en 8 uur duurt, wordt het toevoegen van 8 uur aan de TimeOnly structuur overgerold tot 2:00 uur.
  • Als DateTime u een tijd van de dag gebruikt, moet een willekeurige datum worden gekoppeld aan de tijd en later genegeerd. Het is gebruikelijk om (0001-01-01) te kiezen DateTime.MinValue als de datum, maar als uren worden afgetrokken van de DateTime waarde, kan er een OutOfRange uitzondering optreden. TimeOnly heeft dit probleem niet omdat de tijd rond de periode van 24 uur vooruit en achteruit rolt.
  • Het serialiseren van een DateTime structuur omvat het datumonderdeel, waardoor de intentie van de gegevens mogelijk wordt verborgen. TimeOnly Serialiseert ook minder gegevens.

Zie De structuren DateOnly en TimeOnly gebruiken voor meer informatie.TimeOnly

Belangrijk

TimeOnly is niet beschikbaar in .NET Framework.

De klasse TimeZoneInfo

De TimeZoneInfo klasse vertegenwoordigt een van de tijdzones van de aarde en maakt het mogelijk om een datum en tijd in één tijdzone te converteren naar het equivalent ervan in een andere tijdzone. De TimeZoneInfo klasse maakt het mogelijk om met datums en tijden te werken, zodat elke datum- en tijdwaarde ondubbelzinnig één bepaald tijdstip identificeert. De TimeZoneInfo klasse is ook uitbreidbaar. Hoewel deze afhankelijk is van tijdzone-informatie die is opgegeven voor Windows-systemen en gedefinieerd in het register, ondersteunt het maken van aangepaste tijdzones. Het ondersteunt ook de serialisatie en deserialisatie van tijdzone-informatie.

In sommige gevallen kan het volledig profiteren van de TimeZoneInfo klasse verdere ontwikkeling vereisen. Als datum- en tijdwaarden niet nauw zijn gekoppeld aan de tijdzones waartoe ze behoren, is verder werk vereist. Tenzij uw toepassing een mechanisme biedt voor het koppelen van een datum en tijd aan de bijbehorende tijdzone, is het eenvoudig dat een bepaalde datum- en tijdwaarde wordt ontkoppeld van de tijdzone. Een methode voor het koppelen van deze informatie is het definiëren van een klasse of structuur die zowel de datum- als tijdwaarde en het bijbehorende tijdzoneobject bevat.

Als u wilt profiteren van de ondersteuning voor tijdzones in .NET, moet u de tijdzone kennen waartoe een datum- en tijdwaarde behoort wanneer dat datum- en tijdobject wordt geïnstantieerd. De tijdzone is vaak niet bekend, met name in web- of netwerk-apps.

Zie ook