Sdílet prostřednictvím


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

Přestože obě struktury DateTime a DateTimeOffset poskytují členy, kteří provádějí aritmetické operace s jejich hodnotami, jsou výsledky aritmetických operací velmi odlišné. Toto téma popisuje tyto rozdíly, které se vztahují na časová pásma data a času a popisuje, jak provádět operace s datumovými a časovými údaji s ohledem na časová pásma.

Porovnání a aritmetické operace s hodnotami DateTime

Počínaje rozhraním .NET Framework verze 2.0, hodnoty DateTime mají omezené povědomí o časovém pásmu. Vlastnost DateTime.Kind umožňuje přiřadit hodnotu DateTimeKind pro datum a čas pro označení, zda představuje místní čas, koordinovaný světový čas (standard UTC) nebo čas v nespecifikovaném časovém pásmu. Avšak tato omezená informace o časovém pásmu je ignorována při porovnávání nebo provádění datumových a časových aritmetických operací u hodnot DateTime. To ukazuje následující příklad, který porovnává aktuální místní čas s aktuálním časem UTC.

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
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.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(typeof(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.                                                    

Metoda CompareTo(DateTime) hlásí, že místní čas je dřívější (nebo menší než) čas UTC a operace odčítání určuje rozdíl mezi časem UTC a místním časem pro systém v USA. Standardní časové pásmo v Tichomoří je sedm hodin. Vzhledem k tomu, že tyto dvě hodnoty poskytují různé reprezentace jednoho časového údaje, je v tomto případě zřejmé, že tento časový interval je zcela odvoditelný z místního časového pásma a posunu od času UTC.

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

  • Výsledek jakékoli aritmetické operace provedené na dvou hodnotách data a času, jejichž obě vlastnosti DateTime.Kind se rovnají Utc, odráží skutečný časový interval mezi těmito dvěmi hodnotami. Podobně, porovnání dvou takovýchto hodnot data a času přesně odráží vztah mezi časy.

  • Výsledek jakékoli aritmetické operace nebo porovnání prováděného na dvou hodnotách data a času jejichž vlastnosti DateTime.Kind se obě rovnají Local nebo na dvou hodnotách data a času s různými hodnotami vlastností DateTime.Kind odráží rozdíl v čase mezi těmito dvěmi hodnotami.

  • Aritmetické operace nebo operace porovnávání na místních hodnotách data a času nezohledňují, zda konkrétní hodnota je dvojznačná nebo neplatná, ani neberou v úvahu účinek pravidel pro úpravu, která vyplývají z přechodu z místního časového pásma na letní čas nebo naopak.

  • Jakákoli operace, která porovnává nebo počítá rozdíl mezi místním časem a časem UTC obsahuje časový interval, který se rovná posunu místního časového pásma od času UTC.

  • Jakákoli operace, která porovnává nebo počítá rozdíl mezi časem s neurčenou časovou zónou a časem UTC nebo místním časem bere v úvahu čas bez časové zóny. Rozdíly v časových pásmech nejsou zohledněny a výsledek nezohledňuje uplatňovaná pravidla úpravy časových pásem.

  • Jakákoli operace, která porovnává nebo vypočítává rozdíl mezi dvěmi nespecifikovanými časy může vložit neznámý interval odpovídající rozdílu mezi časem ve dvou různých časových pásmech.

Existuje mnoho scénářů, ve kterých rozdíly v časových pásmech nemají vliv na výpočty s datem a časem (pro diskusi k tomuto viz: Volba mezi DateTime, DateTimeOffset a TimeZoneInfo) nebo ve kterých kontext data a času určuje význam porovnává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 tento datum a času vzhledem k času UTC. Díky tomu je možné definovat rovnost trochu jinak než pro hodnoty DateTime. Zatímco hodnoty DateTime jsou rovny, pokud mají stejné hodnoty data a času, hodnoty DateTimeOffset jsou rovny, pokud obě odkazují na stejný bod v čase. Díky tomu je hodnota DateTimeOffset přesnější a méně náročná na interpretaci, v případě použití při porovnávání a u většiny aritmetických operací, které určující interval mezi dvěma daty a časy. Následující příklad, který je DateTimeOffset ekvivalentem k předchozímu příkladu, který porovnával hodnoty místního času a času UTC DateTime, ukazuje rozdíl v chování.

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

V tomto příkladu metoda CompareTo označuje, že aktuální místní čas a aktuální čas UTC se rovnají a odečtení od hodnot DateTimeOffset označuje, že rozdíl mezi dvěma časy je TimeSpan.Zero.

Hlavní omezení použití hodnot DateTimeOffset pro aritmetické operace s daty a časem je, že ačkoli hodnoty DateTimeOffset zohledňují částečně časové pásmo, tak časové pásmo nezohledňují úplně. Přestože hodnoty posunu DateTimeOffset zohledňují posun časového pásma od času UTC, tak když je proměnné DateTimeOffset nejprve přiřazena hodnota, tak se informace o časovém pásmu zruší. Protože už není přímo spojena s identifikací času, sčítání a odčítání intervalů pro data a čas nezohledňuje pravidla pro časové pásma.

Pro ukázku je znázorněn přechod na letní čas ve Standardním centrálním časovém pásmu v USA ve 2:00 dopoledne. 30. března 2007 v 02:00:00 To znamená, že přidání intervalu dvou a půl hodin k standardnímu centrální času 1:30 dopoledne 9. března 2008 má vracet datum a čas 5:00 dopoledne. 30. března 2008. Avšak jak ukazuje následující příklad, výsledek přidání je 4:00 dopoledne. 9. března 2008. Všimněte si, že výsledek této operace představuje konkrétní bod v čase, ačkoli to není čas v časovém pásmu, které nás zajímá (to znaméná, že nemá očekávaný posun časového pásma).

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

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

Třída TimeZoneInfo obsahuje řadu metod pro převod, které automaticky aplikují úpravy při převodu časů z jednoho časové pásma do jiného. Například:

Další informace naleznete v tématu: Převod časů mezi časovými pásmy.

Třída TimeZoneInfo neposkytuje metody, které automaticky používají pravidla pro úpravy při provádění aritmetických operací s daty a časem. Avšak toto lze provést převodem času s časovým pásmem na čas UTC, provést aritmetické operace a potom převést čas z času UTC zpět na čas s časovým pásmem. Další informace naleznete v tématu: Postupy: Použití časových pásem v aritmetických operacích s daty a časy.

Například následující kód je podobný jako předchozí kód, který přidal dvě a půl hodiny k 2 00 dopoledne. 9. března 2008. Avšak, protože převádí standardní centrální čas na čas UTC před prováděním aritmetických operací s datem a časem a poté převede výsledek z času UTC zpět na standardní centrální čas, výsledný čas zohledňuje posun na letní čas u centrální časové zóny.

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

Viz také

Úkoly

Postupy: Použití časových pásem v aritmetických operacích s daty a časy

Další zdroje

Data, časy a časových pásem