Postupy: Používání časových pásem v aritmetice kalendářních a časových údajů

Obvykle platí, že pokud provádíte aritmetické aritmetické DateTimeDateTimeOffset hodnoty kalendářního data a času, výsledek neodráží žádná pravidla pro úpravy časového pásma. To platí i v případě, že časové pásmo hodnoty data a času je jasně identifikovatelné (například když Kind je vlastnost nastavena na Local). Toto téma ukazuje, jak provádět aritmetické operace s hodnotami data a času, které patří do určitého časového pásma. Výsledky aritmetických operací budou odrážet pravidla úprav časového pásma.

Použití pravidel úpravy na aritmetické aritmetické datum a čas

  1. Implementujte určitou metodu úzce spárované hodnoty data a času s časovým pásmem, ke kterému patří. Deklarujte například strukturu, která zahrnuje hodnotu data a času i její časové pásmo. Následující příklad používá tento přístup k propojení hodnoty s časovým DateTime pásmem.

    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
       TimeZoneInfo TimeZone;
       DateTime Time;
    }
    
    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
        Dim TimeZone As TimeZoneInfo
        Dim Time As Date
    End Structure
    
  2. Převeďte čas na koordinovaný univerzální čas (UTC) voláním ConvertTimeToUtc metody nebo ConvertTime metody.

  3. Proveďte aritmetickou operaci v čase UTC.

  4. Převeďte čas z UTC na časové pásmo přidružené k původnímu času voláním TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) metody.

Příklad

Následující příklad přidá dvě hodiny a třicet minut do 9. března 2008 v 1:30 střední standardní čas. Přechod časového pásma na letní čas nastane o třicet minut později v 9. březnu 2008 v 2:00. Vzhledem k tomu, že příklad se řídí čtyřmi kroky uvedenými v předchozí části, správně hlásí výsledný čas 9. března 2008 jako 5:00.

using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTime Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTime time)
   {
      if (tz == null)
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime,
                              TimeZoneInfo.Utc, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

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

         cstTime1 = new TimeZoneTime(cst, time1);
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
                                                    twoAndAHalfHours.ToString(),
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}
Public Structure TimeZoneTime
    Public TimeZone As TimeZoneInfo
    Public Time As Date

    Public Sub New(tz As TimeZoneInfo, time As Date)
        If tz Is Nothing Then _
           Throw New ArgumentNullException("The time zone cannot be a null reference.")

        Me.TimeZone = tz
        Me.Time = time
    End Sub

    Public Function AddTime(interval As TimeSpan) As TimeZoneTime
        ' Convert time to UTC
        Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
                                                                Me.TimeZone)
        ' Add time interval to time
        utcTime = utcTime.Add(interval)
        ' Convert time back to time in time zone
        Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
                                TimeZoneInfo.Utc, Me.TimeZone))
    End Function
End Structure

Module TimeArithmetic
    Public Const tzName As String = "Central Standard Time"

    Public Sub Main()
        Try
            Dim cstTime1, cstTime2 As TimeZoneTime

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

            cstTime1 = New TimeZoneTime(cst, time1)
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

            Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                       twoAndAHalfHours.ToString(), _
                                                       cstTime2.Time)
        Catch
            Console.WriteLine("Unable to find {0}.", tzName)
        End Try
    End Sub
End Module

Obě DateTime hodnoty DateTimeOffset se oddělují od jakéhokoli časového pásma, do kterého můžou patřit. Aby bylo možné provádět aritmetické aritmetické hodnoty data a času způsobem, který automaticky použije pravidla úpravy časového pásma, musí být časové pásmo, do kterého patří jakákoli hodnota data a času, okamžitě identifikovatelná. To znamená, že datum a čas a jeho přidružené časové pásmo musí být úzce svázané. Existuje několik způsobů, jak to udělat, mezi které patří:

  • Předpokládejme, že všechny časy používané v aplikaci patří do určitého časového pásma. I když je tento přístup v některých případech vhodný, nabízí omezenou flexibilitu a možná omezenou přenositelnost.

  • Definujte typ, který úzce páruje datum a čas s přidruženým časovým pásmem, a to tak, že zahrne obě pole typu. Tento přístup se používá v příkladu kódu, který definuje strukturu pro uložení data a času a časového pásma ve dvou polích členů.

Tento příklad ukazuje, jak provádět aritmetické operace s DateTime hodnotami, aby se na výsledek použila pravidla úpravy časového pásma. DateTimeOffset Hodnoty se ale dají použít stejně snadno. Následující příklad ukazuje, jak může být kód v původním příkladu upraven tak, aby používal DateTimeOffset místo DateTime hodnot.

using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTimeOffset Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
   {
      if (tz == null)
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

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

         cstTime1 = new TimeZoneTime(cst,
                        new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
                                                    twoAndAHalfHours.ToString(),
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}
Public Structure TimeZoneTime
    Public TimeZone As TimeZoneInfo
    Public Time As DateTimeOffset

    Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
        If tz Is Nothing Then _
           Throw New ArgumentNullException("The time zone cannot be a null reference.")

        Me.TimeZone = tz
        Me.Time = time
    End Sub

    Public Function AddTime(interval As TimeSpan) As TimeZoneTime
        ' Convert time to UTC
        Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)
        ' Add time interval to time
        utcTime = utcTime.Add(interval)
        ' Convert time back to time in time zone
        Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
    End Function
End Structure

Module TimeArithmetic
    Public Const tzName As String = "Central Standard Time"

    Public Sub Main()
        Try
            Dim cstTime1, cstTime2 As TimeZoneTime

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

            cstTime1 = New TimeZoneTime(cst, _
                           New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

            Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                       twoAndAHalfHours.ToString(), _
                                                       cstTime2.Time)
        Catch
            Console.WriteLine("Unable to find {0}.", tzName)
        End Try
    End Sub
End Module

Všimněte si, že pokud je toto sčítání jednoduše provedeno s DateTimeOffset hodnotou bez prvního převodu na UTC, výsledek odráží správný bod v čase, ale jeho posun neodráží hodnotu určeného časového pásma pro daný čas.

Zkompilování kódu

Tento příklad vyžaduje:

  • Že se System obor názvů importuje pomocí using příkazu (vyžaduje se v kódu jazyka C#).

Viz také