Dela via


Utföra aritmetiska åtgärder med datum och tider

Även om både strukturerna DateTime och DateTimeOffset ger medlemmar som utför aritmetiska åtgärder på sina värden, skiljer sig resultaten från aritmetiska åtgärder mycket olika. Den här artikeln undersöker dessa skillnader, relaterar dem till grader av tidszonsmedvetenhet i datum- och tidsdata och beskriver hur du utför fullständigt tidszonsmedvetna åtgärder med hjälp av datum- och tidsdata.

Jämförelser och aritmetiska åtgärder med DateTime-värden

Egenskapen DateTime.Kind tillåter att ett DateTimeKind värde tilldelas till datum och tid för att ange om det representerar lokal tid, UTC (Coordinated Universal Time) eller tiden i en ospecificerad tidszon. Den här begränsade tidszonsinformationen ignoreras dock när du jämför eller utför datum- och tidsaritmetik för DateTimeKind värden. I följande exempel, som jämför den aktuella lokala tiden med den aktuella UTC-tiden, visas hur tidszonsinformationen ignoreras.

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

Metoden CompareTo(DateTime) rapporterar att den lokala tiden är tidigare än (eller mindre än) UTC-tiden, och subtraktionsåtgärden anger att skillnaden mellan UTC och den lokala tiden för ett system i U.S. Pacific Standard Time-zonen är sju timmar. Men eftersom dessa två värden ger olika representationer av en enskild tidpunkt är det i det här fallet tydligt att tidsintervallet helt kan tillskrivas den lokala tidszonens förskjutning från UTC.

Mer allmänt DateTime.Kind påverkar egenskapen inte de resultat som returneras med Kind jämförelse- och aritmetiska metoder (som jämförelsen av två identiska tidpunkter indikerar), även om det kan påverka tolkningen av dessa resultat. Till exempel:

  • Resultatet av en aritmetikåtgärd som utförs på två datum- och tidsvärden vars egenskaper båda är lika DateTimeKind återspeglar det faktiska tidsintervallet DateTime.Kind mellan de två värdena. På samma sätt återspeglar jämförelsen av två sådana datum- och tidsvärden korrekt relationen mellan tider.

  • Resultatet av en aritmetik- eller jämförelseåtgärd som utförs på två datum- och tidsvärden vars egenskaper både är lika DateTimeKind med eller på två datum- och tidsvärden DateTime.Kind med olika DateTime.Kind egenskapsvärden återspeglar skillnaden i klocktid mellan de två värdena.

  • Aritmetiska åtgärder eller jämförelseåtgärder för lokala datum- och tidsvärden tar inte hänsyn till om ett visst värde är tvetydigt eller ogiltigt, och de tar inte heller hänsyn till effekten av eventuella justeringsregler som beror på den lokala tidszonens övergång till eller från sommartid.

  • Alla åtgärder som jämför eller beräknar skillnaden mellan UTC och en lokal tid innehåller ett tidsintervall som är lika med den lokala tidszonens förskjutning från UTC i resultatet.

  • Alla åtgärder som jämför eller beräknar skillnaden mellan en ospecificerad tid och antingen UTC eller den lokala tiden återspeglar enkel klocktid. Tidszonsskillnader beaktas inte och resultatet återspeglar inte tillämpningen av tidszonsjusteringsregler.

  • Alla åtgärder som jämför eller beräknar skillnaden mellan två ospecificerade tider kan innehålla ett okänt intervall som återspeglar skillnaden mellan tiden i två olika tidszoner.

Det finns många scenarier där tidszonsskillnader inte påverkar datum- och tidsberäkningar (för en diskussion om några av dessa scenarier finns i Välja mellan DateTime, DateTimeOffset, TimeSpan och TimeZoneInfo) eller där kontexten för datum- och tidsdata definierar innebörden av jämförelse- eller aritmetiska åtgärder.

Jämförelser och aritmetiska åtgärder med DateTimeOffset-värden

Ett DateTimeOffset värde innehåller inte bara ett datum och en tid, utan även en förskjutning som entydigt definierar datum och tid i förhållande till UTC. Den här förskjutningen gör det möjligt att definiera likhet på ett annat sätt än för DateTime värden. Medan DateTime värdena är lika om de har samma datum- och tidsvärde, DateTimeOffset är värdena lika om de båda refererar till samma tidpunkt. När det används i jämförelser och i de flesta aritmetiska åtgärder som bestämmer intervallet mellan två datum och tider, är ett DateTimeOffset värde mer exakt och mindre i behov av tolkning. Följande exempel, som motsvarar DateTimeOffset föregående exempel som jämförde lokala värden och UTC-värden DateTimeOffset , illustrerar den här skillnaden i beteende.

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)

I det här exemplet CompareTo anger metoden att den aktuella lokala tiden och den aktuella UTC-tiden är lika med, och subtraktion av CompareTo(DateTimeOffset) värden anger att skillnaden mellan de två gångerna är TimeSpan.Zero.

Den främsta begränsningen med att använda DateTimeOffset värden i datum- och tidsaritmetik är att även om DateTimeOffset värden har viss tidszonsmedvetenhet är de inte helt tidszonsmedvetna. DateTimeOffset Även om värdets förskjutning återspeglar en tidszons förskjutning från UTC när en DateTimeOffset variabel först tilldelas ett värde, kopplas den bort från tidszonen därefter. Eftersom den inte längre är direkt associerad med en identifierbar tid, beaktar inte tillägget och subtraktionen av datum- och tidsintervallen en tidszons justeringsregler.

För att illustrera, övergången till sommartid i US Central Standard Tidszon sker klockan 02:00 den 9 mars 2008. Med detta i åtanke bör tillägg av ett intervall på två och en halv timme till en central standardtid på 01:30 den 9 mars 2008 generera ett datum och en tid på 05:00 den 9 mars 2008. Men som följande exempel visar är resultatet av tillägget 04:00 den 9 mars 2008. Resultatet av den här åtgärden representerar rätt tidpunkt, även om det inte är den tid i tidszonen som vi är intresserade av (det vill: den har inte den förväntade tidszonsförskjutningen).

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

Aritmetiska åtgärder med tider i tidszoner

Klassen TimeZoneInfo innehåller konverteringsmetoder som automatiskt tillämpar justeringar när de konverterar tider från en tidszon till en annan. Dessa konverteringsmetoder omfattar:

Mer information finns i Konvertera tider mellan tidszoner.

Klassen TimeZoneInfo tillhandahåller inga metoder som automatiskt tillämpar justeringsregler när du utför datum- och tidsaritmetik. Du kan dock tillämpa justeringsregler genom att konvertera tiden i en tidszon till UTC, utföra den aritmetiska åtgärden och sedan konvertera från UTC tillbaka till tiden i tidszonen. Mer information finns i Så här använder du tidszoner i datum- och tidsaritmetik.

Följande kod liknar till exempel den tidigare koden som lade till två och en halv timme till 02:00 den 9 mars 2008. Men eftersom den konverterar en central standardtid till UTC innan den utför datum- och tidsaritmetik och sedan konverterar resultatet från UTC tillbaka till Central Standard-tid, återspeglar den resulterande tiden den centrala standardtidszonens övergång till sommartid.

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

Se även