Durchführen arithmetischer Datums- und Uhrzeitoperationen

Obwohl sowohl die -Struktur als auch DateTime die DateTimeOffset -Struktur Member bereitstellen, die arithmetische Operationen für ihre Werte ausführen, sind die Ergebnisse arithmetischer Operationen sehr unterschiedlich. In diesem Artikel werden diese Unterschiede untersucht und mit dem Grad der Unterstützung von Zeitzonen bei Datums- und Zeitdaten in Zusammenhang gebracht. Zudem wird erläutert, wie Operationen mit Datums- und Uhrzeitdaten unter vollständiger Berücksichtigung der Zeitzone durchgeführt werden.

Vergleiche und arithmetische Operationen mit DateTime-Werten

Die DateTime.Kind -Eigenschaft ermöglicht es, dem Datum und der Uhrzeit einen DateTimeKind Wert zuzuweisen, um anzugeben, ob er die Ortszeit, koordinierte Weltzeit (UTC) oder die Uhrzeit in einer nicht angegebenen Zeitzone darstellt. Diese eingeschränkten Zeitzoneninformationen werden jedoch beim Vergleichen oder Ausführen von Datums- und Uhrzeitarithmetik für DateTimeKind -Werte ignoriert. Im folgenden Beispiel, das die aktuelle Ortszeit mit der aktuellen UTC-Zeit vergleicht, wird veranschaulicht, wie die Zeitzoneninformationen ignoriert werden.

using System;

public enum TimeComparison
{
   EarlierThan = -1,
   TheSameAs = 0,
   LaterThan = 1
}

public class DateManipulation
{
   public static void Main()
   {
      DateTime localTime = DateTime.Now;
      DateTime utcTime = DateTime.UtcNow;

      Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours",
                        localTime.Kind,
                        utcTime.Kind,
                        (localTime - utcTime).Hours,
                        (localTime - utcTime).Minutes);
      Console.WriteLine("The {0} time is {1} the {2} time.",
                        localTime.Kind,
                        Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime)),
                        utcTime.Kind);
   }
}
// If run in the U.S. Pacific Standard Time zone, the example displays
// the following output to the console:
//    Difference between Local and Utc time: -7:0 hours
//    The Local time is EarlierThan the Utc time.
Public Enum TimeComparison As Integer
    EarlierThan = -1
    TheSameAs = 0
    LaterThan = 1
End Enum

Module DateManipulation
    Public Sub Main()
        Dim localTime As Date = Date.Now
        Dim utcTime As Date = Date.UtcNow

        Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours", _
                          localTime.Kind.ToString(), _
                          utcTime.Kind.ToString(), _
                          (localTime - utcTime).Hours, _
                          (localTime - utcTime).Minutes)
        Console.WriteLine("The {0} time is {1} the {2} time.", _
                          localTime.Kind.ToString(), _
                          [Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)), _
                          utcTime.Kind.ToString())
        ' If run in the U.S. Pacific Standard Time zone, the example displays 
        ' the following output to the console:
        '    Difference between Local and Utc time: -7:0 hours
        '    The Local time is EarlierThan the Utc time.                                                    
    End Sub
End Module

Die CompareTo(DateTime) -Methode meldet, dass die lokale Zeit vor (oder kleiner als) der UTC-Zeit liegt, und der Subtraktionsvorgang gibt an, dass der Unterschied zwischen UTC und der Ortszeit für ein System in der Zeitzone "USA Pacific Standard Time" sieben Stunden beträgt. Da diese beiden Werte jedoch unterschiedliche Darstellungen eines einzelnen Zeitpunkts bereitstellen, ist in diesem Fall klar, dass das Zeitintervall vollständig auf den Offset der lokalen Zeitzone von UTC zurückzuführen ist.

Im Allgemeinen wirkt sich die DateTime.Kind -Eigenschaft nicht auf die Ergebnisse aus, die von Vergleichs- und arithmetischen Methoden zurückgegeben werden Kind (wie der Vergleich zweier identischer Zeitpunkte angibt), obwohl sie sich auf die Interpretation dieser Ergebnisse auswirken kann. Beispiel:

  • Das Ergebnis einer arithmetischen Operation, die mit zwei Datums- und Uhrzeitwerten ausgeführt wird, deren DateTime.Kind Eigenschaften beide dem DateTimeKind tatsächlichen Zeitintervall zwischen den beiden Werten entsprechen. Entsprechend gibt der Vergleich zweier solcher Datums- und Zeitwerte genau die Beziehung zwischen den Zeiten wieder.

  • Das Ergebnis eines arithmetischen Vorgangs oder Vergleichsvorgangs, der mit zwei Datums- und Uhrzeitwerten durchgeführt wird, deren DateTime.Kind Eigenschaften beide gleich oder an zwei DateTimeKind Datums- und Uhrzeitwerten mit DateTime.Kind unterschiedlichen Eigenschaftswerten sind, spiegelt den Unterschied in der Uhrzeit zwischen den beiden Werten wider.

  • Bei arithmetischen oder Vergleichsoperationen für lokale Datums- und Uhrzeitwerte wird nicht berücksichtigt, ob ein bestimmter Wert mehrdeutig oder ungültig ist. Ebenso wenig werden die Auswirkungen von Anpassungsregeln berücksichtigt, die sich aus dem Übergang der lokalen Zeitzone zu oder von der Sommerzeit ergeben.

  • Jeder Vorgang, bei dem die Differenz zwischen UTC und einer lokalen Zeit verglichen oder berechnet wird, umfasst im Ergebnis ein Zeitintervall, das der Abweichung der lokalen Zeitzone von UTC entspricht.

  • Jeder Vorgang, bei dem die Differenz zwischen einer nicht spezifizierten Uhrzeit und UTC oder der Ortszeit verglichen oder berechnet wird, gibt die einfache Uhrzeit wieder. Zeitzonenunterschiede werden nicht berücksichtigt, und das Ergebnis gibt nicht die Anwendung der Regeln zur Zeitzonenanpassung wieder.

  • Jeder Vorgang, bei dem die Differenz zwischen zwei nicht spezifizierten Zeiten verglichen oder berechnet wird, kann ein unbekanntes Intervall umfassen, das den Unterschied zwischen den Zeiten in zwei verschiedenen Zeitzonen wiedergibt.

Es gibt viele Szenarien, in denen Sich Zeitzonenunterschiede nicht auf Datums- und Uhrzeitberechnungen auswirken (eine Erörterung einiger dieser Szenarien finden Sie unter Auswählen zwischen DateTime, DateTimeOffset, TimeSpan und TimeZoneInfo),oder in denen der Kontext der Datums- und Uhrzeitdaten die Bedeutung von Vergleichs- oder arithmetischen Operationen definiert.

Vergleiche und arithmetische Operationen mit DateTimeOffset-Werten

Ein -Wert enthält nicht nur ein Datum und eine Uhrzeit, sondern auch einen Offset, der das Datum und die Uhrzeit relativ zur DateTimeOffset UTC eindeutig definiert. Dieser Offset ermöglicht es, Gleichheit anders als für -Werte DateTime zu definieren. Während Werte gleich sind, wenn sie den gleichen Datums- und Uhrzeitwert haben, sind die Werte gleich, wenn sie DateTime DateTimeOffset beide auf denselben Zeitpunkt verweisen. Bei Verwendung in Vergleichen und in den meisten arithmetischen Operationen, die das Intervall zwischen zwei Datumsangaben und Zeiten bestimmen, ist ein Wert genauer und benötigt weniger DateTimeOffset Interpretation. Das folgende Beispiel, das dem vorherigen Beispiel entspricht, in dem lokale Werte und UTC-Werte verglichen DateTimeOffset DateTimeOffset wurden, veranschaulicht diesen Unterschied im Verhalten.

using System;

public enum TimeComparison
{
   EarlierThan = -1,
   TheSameAs = 0,
   LaterThan = 1
}

public class DateTimeOffsetManipulation
{
   public static void Main()
   {
      DateTimeOffset localTime = DateTimeOffset.Now;
      DateTimeOffset utcTime = DateTimeOffset.UtcNow;

      Console.WriteLine("Difference between local time and UTC: {0}:{1:D2} hours",
                        (localTime - utcTime).Hours,
                        (localTime - utcTime).Minutes);
      Console.WriteLine("The local time is {0} UTC.",
                        Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime)));
   }
}
// Regardless of the local time zone, the example displays
// the following output to the console:
//    Difference between local time and UTC: 0:00 hours.
//    The local time is TheSameAs UTC.
Public Enum TimeComparison As Integer
    EarlierThan = -1
    TheSameAs = 0
    LaterThan = 1
End Enum

Module DateTimeOffsetManipulation
    Public Sub Main()
        Dim localTime As DateTimeOffset = DateTimeOffset.Now
        Dim utcTime As DateTimeOffset = DateTimeOffset.UtcNow

        Console.WriteLine("Difference between local time and UTC: {0}:{1:D2} hours.", _
                          (localTime - utcTime).Hours, _
                          (localTime - utcTime).Minutes)
        Console.WriteLine("The local time is {0} UTC.", _
                          [Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)))
    End Sub
End Module
' Regardless of the local time zone, the example displays 
' the following output to the console:
'    Difference between local time and UTC: 0:00 hours.
'    The local time is TheSameAs UTC.
'          Console.WriteLine(e.GetType().Name)

In diesem Beispiel gibt die -Methode an, dass die aktuelle Ortszeit und die aktuelle UTC-Zeit gleich sind, und die Subtraktion von -Werten gibt an, dass der Unterschied zwischen den beiden -Werten CompareTo CompareTo(DateTimeOffset) TimeSpan.Zero ist.

Die Hauptbeschränkung bei der Verwendung von Werten in der Datums- und Uhrzeitarithmetik besteht in der Tatsache, dass Werte zwar über ein gewisses Zeitzonenbewusstsein verfügen, aber nicht vollständig DateTimeOffset DateTimeOffset zeitzonenbewusst sind. Obwohl der Offset des Werts den Offset einer Zeitzone von UTC widerspiegelt, wenn einer Variablen zum ersten Mal ein Wert zugewiesen wird, wird sie danach von der DateTimeOffset DateTimeOffset Zeitzone entfernt. Da er nicht mehr direkt einer identifizierbaren Zeit zugeordnet ist, werden bei der Addition und Subtraktion von Datums- und Uhrzeitintervallen keine Regeln zur Zeitzonenanpassung berücksichtigt.

Zur Veranschaulichung erfolgt der Übergang zur Sommerzeit in der Zeitzone "USA, Mitte Normalzeit" um 2:00 Uhr am 9. März 2008 hinzugefügt wurden. Vor diesem Hintergrund wird ein Intervall von zweieinhalb Stunden zu einer zentralen Standardzeit von 1:30 Uhr hinzugefügt. am 9. März 2008 ein Datum und eine Uhrzeit von 5:00 Uhr morgens am 9. März 2008 hinzugefügt wurden. Wie das folgende Beispiel zeigt, ist das Ergebnis der Addition jedoch 4:00 Uhr morgens am 9. März 2008 hinzugefügt wurden. Das Ergebnis dieses Vorgangs stellt den richtigen Zeitpunkt dar, obwohl es sich nicht um die Zeit in der Zeitzone handelt, an der wir interessiert sind (d. b. es hat nicht den erwarteten Zeitzonenoffset).

using System;

public class IntervalArithmetic
{
   public static void Main()
   {
      DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
      const string tzName = "Central Standard Time";
      TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

      // Instantiate DateTimeOffset value to have correct CST offset
      try
      {
         DateTimeOffset centralTime1 = new DateTimeOffset(generalTime,
                    TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime));

         // Add two and a half hours
         DateTimeOffset centralTime2 = centralTime1.Add(twoAndAHalfHours);
         // Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1,
                                                    twoAndAHalfHours.ToString(),
                                                    centralTime2);
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
      }
   }
}
// The example displays the following output to the console:
//    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00
Module IntervalArithmetic
    Public Sub Main()
        Dim generalTime As Date = #03/09/2008 1:30AM#
        Const tzName As String = "Central Standard Time"
        Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

        ' Instantiate DateTimeOffset value to have correct CST offset
        Try
            Dim centralTime1 As New DateTimeOffset(generalTime, _
                       TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime))

            ' Add two and a half hours      
            Dim centralTime2 As DateTimeOffset = centralTime1.Add(twoAndAHalfHours)
            ' Display result
            Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
                                                       twoAndAHalfHours.ToString(), _
                                                       centralTime2)
        Catch e As TimeZoneNotFoundException
            Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
        End Try
    End Sub
End Module
' The example displays the following output to the console:
'    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00

Arithmetische Operationen mit Uhrzeiten in Zeitzonen

Die TimeZoneInfo -Klasse enthält Konvertierungsmethoden, die automatisch Anpassungen anwenden, wenn sie Zeiten von einer Zeitzone in eine andere konvertieren. Zu diesen Konvertierungsmethoden gehören:

Weitere Informationen finden Sie unter Konvertieren von Zeiten zwischen Zeitzonen.

Die TimeZoneInfo -Klasse stellt keine Methoden bereit, die automatisch Anpassungsregeln anwenden, wenn Sie Arithmetik für Datum und Uhrzeit ausführen. Sie können jedoch Anpassungsregeln anwenden, indem Sie die Zeit in einer Zeitzone in UTC konvertieren, die arithmetische Operation ausführen und dann von UTC zurück in die Zeit in der Zeitzone konvertieren. Weitere Informationen finden Sie unter Vorgehensweise: Verwenden von Zeitzonen in arithmetischen Datums- und Uhrzeitangaben.

Beispielsweise ähnelt der folgende Code dem vorherigen Code, bei dem 2,5 Stunden zu 2:00 Uhr am 9. März 2008 hinzugefügt wurden. Da jedoch vor dem Ausführen von Datums- und Uhrzeitoperationen die Central Standard Time in UTC konvertiert und das Ergebnis dann von UTC zurück in Central Standard Time zurückkonvertiert wird, gibt die Ergebniszeit den Übergang von der Zeitzone Central Standard Time zur Sommerzeit wieder.

using System;

public class TimeZoneAwareArithmetic
{
   public static void Main()
   {
      const string tzName = "Central Standard Time";

      DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
      TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
      TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

      // Instantiate DateTimeOffset value to have correct CST offset
      try
      {
         DateTimeOffset centralTime1 = new DateTimeOffset(generalTime,
                                       cst.GetUtcOffset(generalTime));

         // Add two and a half hours
         DateTimeOffset utcTime = centralTime1.ToUniversalTime();
         utcTime += twoAndAHalfHours;

         DateTimeOffset centralTime2 = TimeZoneInfo.ConvertTime(utcTime, cst);
         // Display result
         Console.WriteLine("{0} + {1} hours = {2}", centralTime1,
                                                    twoAndAHalfHours.ToString(),
                                                    centralTime2);
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
      }
   }
}
// The example displays the following output to the console:
//    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00
Module TimeZoneAwareArithmetic
    Public Sub Main()
        Const tzName As String = "Central Standard Time"

        Dim generalTime As Date = #03/09/2008 1:30AM#
        Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
        Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

        ' Instantiate DateTimeOffset value to have correct CST offset
        Try
            Dim centralTime1 As New DateTimeOffset(generalTime, _
                       cst.GetUtcOffset(generalTime))

            ' Add two and a half hours 
            Dim utcTime As DateTimeOffset = centralTime1.ToUniversalTime()
            utcTime += twoAndAHalfHours

            Dim centralTime2 As DateTimeOffset = TimeZoneInfo.ConvertTime(utcTime, cst)
            ' Display result
            Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
                                                       twoAndAHalfHours.ToString(), _
                                                       centralTime2)
        Catch e As TimeZoneNotFoundException
            Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
        End Try
    End Sub
End Module
' The example displays the following output to the console:
'    3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00

Weitere Informationen