Dela via


Anvisningar: Använda tidszoner i datum- och tidsaritmetik

Normalt, när du utför datum- och tidsaritmetik med hjälp av DateTime eller DateTimeOffset värden, återspeglar resultatet inte några regler för tidszonsjustering. Detta gäller även när tidszonen för datum- och tidsvärdet är tydligt identifierbar (till exempel när Kind egenskapen är inställd på Local). Det här avsnittet visar hur du utför aritmetiska åtgärder på datum- och tidsvärden som tillhör en viss tidszon. Resultatet av de aritmetiska åtgärderna återspeglar tidszonens justeringsregler.

Tillämpa justeringsregler på datum- och tidsaritmetik

  1. Implementera någon metod för att nära koppla ett datum- och tidsvärde till den tidszon som den tillhör. Deklarera till exempel en struktur som innehåller både datum- och tidsvärdet och dess tidszon. I följande exempel används den här metoden för att länka ett DateTime värde till tidszonen.

    // 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. Konvertera en tid till Coordinated Universal Time (UTC) genom att anropa antingen ConvertTimeToUtc -metoden eller ConvertTime -metoden.

  3. Utför den aritmetiska åtgärden på UTC-tiden.

  4. Konvertera tiden från UTC till den ursprungliga tidens associerade tidszon genom att anropa TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) metoden.

Exempel

I följande exempel läggs två timmar och trettio minuter till den 9 mars 2008 kl. 01:30 central standardtid. Tidszonens övergång till sommartid inträffar trettio minuter senare, klockan 02:00 den 9 mars 2008. Eftersom exemplet följer de fyra stegen som anges i föregående avsnitt, rapporterar det korrekt den resulterande tiden som 05:00 den 9 mars 2008.

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

Både DateTime värden och DateTimeOffset kopplas från valfri tidszon som de kan tillhöra. Om du vill utföra datum- och tidsaritmetik på ett sätt som automatiskt tillämpar en tidszons justeringsregler måste tidszonen som ett datum- och tidsvärde tillhör omedelbart kunna identifieras. Det innebär att ett datum och en tid och dess associerade tidszon måste vara nära kopplade. Det finns flera sätt att göra detta, bland annat följande:

  • Anta att alla gånger som används i ett program tillhör en viss tidszon. Även om det är lämpligt i vissa fall erbjuder den här metoden begränsad flexibilitet och möjligen begränsad portabilitet.

  • Definiera en typ som nära kopplar samman ett datum och en tid med sin associerade tidszon genom att inkludera båda som fält av typen. Den här metoden används i kodexemplet, som definierar en struktur för att lagra datum och tid och tidszonen i två medlemsfält.

Exemplet illustrerar hur du utför aritmetiska åtgärder på DateTime värden så att tidszonsjusteringsregler tillämpas på resultatet. Värden kan dock DateTimeOffset användas lika enkelt. I följande exempel visas hur koden i det ursprungliga exemplet kan anpassas för användning i stället för DateTimeOffsetDateTime värden.

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

Observera att om det här tillägget bara utförs på DateTimeOffset värdet utan att först konvertera det till UTC, återspeglar resultatet rätt tidpunkt, men dess förskjutning återspeglar inte den avsedda tidszonen för den tiden.

Kompilera koden

Det här exemplet kräver:

  • System Att namnområdet importeras med -instruktionen using (krävs i C#-kod).

Se även