Provádění aritmetických operací s daty a časy

DateTimeDateTimeOffset I když struktury i struktury poskytují členy, které provádějí aritmetické operace s jejich hodnotami, výsledky aritmetických operací jsou velmi odlišné. Tento článek tyto rozdíly zkoumá, spojuje je se stupněm povědomí o časovém pásmu v datech a časech a popisuje, jak provádět plně operace s časovým pásmem pomocí dat data a času.

Porovnání a aritmetické operace s hodnotami DateTime

Tato DateTime.Kind vlastnost umožňuje DateTimeKind přiřadit hodnotu k datu a času, aby určila, zda představuje místní čas, koordinovaný univerzální čas (UTC) nebo čas v nezadaném časovém pásmu. Tyto omezené informace o časovém pásmu se ale ignorují při porovnávání nebo provádění aritmetik data a času u DateTimeKind hodnot. Následující příklad, který porovnává aktuální místní čas s aktuálním časem UTC, ukazuje, jak se informace o časovém pásmu ignorují.

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

Metoda CompareTo(DateTime) hlásí, že místní čas je dřívější než (nebo menší než) čas UTC a operace odčítání označuje, že rozdíl mezi UTC a místním časem systému v americkém standardním časovém pásmu je sedm hodin. Vzhledem k tomu, že tyto dvě hodnoty představují různé vyjádření jednoho bodu v čase, je v tomto případě jasné, že časový interval je zcela způsoben posunem místního časového pásma od času UTC.

Obecněji platí, že DateTime.Kind vlastnost nemá vliv na výsledky vrácené porovnáním Kind a aritmetické metody (jak ukazuje porovnání dvou identických bodů v čase), i když může ovlivnit interpretaci těchto výsledků. Příklad:

  • Výsledek jakékoli aritmetické operace prováděné se dvěma hodnotami data a času, jejichž DateTime.Kind vlastnosti se rovnají DateTimeKind skutečnému časovému intervalu mezi těmito dvěma hodnotami. Podobně porovnání dvou takových hodnot data a času přesně odráží vztah mezi časy.

  • Výsledek jakékoli aritmetické operace nebo operace porovnání prováděné se dvěma hodnotami data a času, jejichž DateTime.Kind vlastnosti jsou stejné DateTimeKind nebo ve dvou hodnotách data a času s různými DateTime.Kind hodnotami vlastností, odráží rozdíl v hodinovém čase mezi těmito dvěma hodnotami.

  • Aritmetické operace nebo operace porovnání místních hodnot data a času nebere v úvahu, zda je určitá hodnota nejednoznačná nebo neplatná, ani nezohlední vliv pravidel úprav, která jsou výsledkem přechodu místního časového pásma na letní čas nebo z letního času.

  • Každá operace, která porovnává nebo vypočítá rozdíl mezi časem UTC a místním časem, zahrnuje časový interval, který se rovná posunu místního časového pásma od času UTC ve výsledku.

  • Jakákoli operace, která porovnává nebo počítá rozdíl mezi nespecifikovaným časem a časem UTC nebo místním časem, odráží jednoduchý hodinový čas. Rozdíly mezi časovými pásmy se nepovažují a výsledek neodráží použití pravidel pro úpravy časového pásma.

  • Každá operace, která porovnává nebo vypočítá rozdíl mezi dvěma nezadanou dobou, může obsahovat neznámý interval, který odráží rozdíl mezi časem ve dvou různých časových pásmech.

Existuje mnoho scénářů, ve kterých rozdíly mezi časovými pásmy nemají vliv na výpočty data a času (pro diskuzi některých z těchto scénářů viz Volba mezi DateTime, DateTimeOffset, TimeSpan a TimeZoneInfo) nebo ve kterých kontext dat data a času definuje význam porovnání nebo aritmetických operací.

Porovnání a aritmetické operace s hodnotami DateTimeOffset

Hodnota DateTimeOffset zahrnuje nejen datum a čas, ale také posun, který jednoznačně definuje datum a čas vzhledem k UTC. Tento posun umožňuje definovat rovnost odlišně než pro DateTime hodnoty. Zatímco DateTime hodnoty jsou stejné, pokud mají stejnou hodnotu data a času, hodnoty jsou stejné, DateTimeOffset pokud obě odkazují na stejný bod v čase. Při použití ve srovnáních a ve většině aritmetických operací, které určují interval mezi dvěma daty a časy, DateTimeOffset je hodnota přesnější a méně v případě potřeby interpretace. Následující příklad, který je DateTimeOffset ekvivalentem předchozího příkladu, který porovnává místní hodnoty a hodnoty UTC DateTimeOffset , ukazuje tento rozdíl v chování.

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)

V tomto příkladu CompareTo metoda označuje, že aktuální místní čas a aktuální čas UTC jsou stejné a odčítání CompareTo(DateTimeOffset) hodnot označuje, že rozdíl mezi těmito dvěma časy je TimeSpan.Zero.

Hlavním omezením používání DateTimeOffset hodnot v aritmetice data a času je, že i když DateTimeOffset mají hodnoty určité povědomí o časovém pásmu, nejsou plně vědomy časového pásma. DateTimeOffset I když posun hodnoty odráží posun časového pásma od času UTC, když DateTimeOffset je proměnná poprvé přiřazena k hodnotě, bude od té doby zrušena od časového pásma. Vzhledem k tomu, že už není přímo spojena s identifikovatelným časem, sčítání a odčítání časových intervalů nepovažuje pravidla úprav časového pásma.

K ilustraci přechodu na letní čas v americkém standardním časovém pásmu dochází v 9. březnu 2008 v 2:00. S ohledem na to by přidání dvou a půlhodinového intervalu do centrálního standardního času 9. března 2008 mělo 9. března 2008 vytvořit datum a čas 9. března 2008. Jak ale ukazuje následující příklad, výsledek přidání je 4:00 do 9. března 2008. Výsledek této operace představuje správný bod v čase, i když se nejedná o čas v časovém pásmu, o které nás zajímá (to znamená, že nemá očekávaný posun časového pásma).

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

Aritmetické operace s časy v časových pásmech

Třída TimeZoneInfo obsahuje metody převodu, které automaticky aplikují úpravy při převodu časů z jednoho časového pásma na jiné. Mezi tyto metody převodu patří:

Podrobnosti najdete v tématu Převod časů mezi časovými pásmy.

Třída TimeZoneInfo neposkytuje žádné metody, které automaticky aplikují pravidla úpravy při provádění aritmetiky data a času. Pravidla úprav ale můžete použít převodem času v časovém pásmu na utc, provedením aritmetické operace a následným převodem z UTC zpět na čas v časovém pásmu. Podrobnosti najdete v tématu Postupy: Použití časových pásem v aritmetice data a času.

Například následující kód je podobný předchozímu kódu, který přidal dvě a půl hodiny do 2:00 do 9. března 2008. Vzhledem k tomu, že před provedením aritmetické aritmetiky data a času převede středový standardní čas na UTC, výsledný čas však odráží přechod centrálního standardního časového pásma na letní čas.

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

Viz také