Condividi tramite


Esecuzione di operazioni aritmetiche con date e ore

Aggiornamento: novembre 2007

Anche se entrambe le strutture DateTime e DateTimeOffset forniscono membri che eseguono operazioni aritmetiche sui relativi valori, i risultati di tali operazioni sono molto diversi. In questo argomento vengono esaminate tali differenze, messe in relazione ai gradi di dipendenza dal fuso orario nei valori di data e ora e viene descritto come eseguire operazioni completamente dipendenti dal fuso orario utilizzando i valori di data e ora.

Confronti e operazioni aritmetiche con i valori DateTime

A partire da .NET Framework versione 2.0, i valori DateTime possiedono un grado limitato di dipendenza dal fuso orario. La proprietà DateTime.Kind consente l'assegnazione di un valore DateTimeKind alla data e all'ora per indicare se rappresenta l'ora locale, l'ora UTC (Coordinated Universal Time) o l'ora di un fuso orario non specificato. Tuttavia, queste limitate informazioni sul fuso orario vengono ignorate quando viene eseguito il confronto oppure operazioni aritmetiche con date e ore su valori DateTime. Nell'esempio seguente, in cui si confronta l'ora locale corrente con l'ora UTC corrente, viene illustrata questa situazione.

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.                                                    

Il metodo CompareTo(DateTime) indica che l'ora locale è precedente, o in altri termini, minore dell'ora UTC e l'operazione di sottrazione indica che la differenza tra l'ora UTC e l'ora locale per un sistema nel fuso Ora solare Pacifico (Stati Uniti) è di sette ore. Ma poiché questi due valori forniscono rappresentazioni diverse di un solo determinato momento, è chiaro in questo caso che tale intervallo di tempo è completamente attribuibile all'offset del fuso orario locale rispetto all'ora UTC.

Più in generale, la proprietà DateTime.Kind non influisce sui risultati restituiti dai metodi di confronto e aritmetici DateTime (come indica il confronto tra due identici momenti), anche se può influire sull'interpretazione di tali risultati. Ad esempio:

  • Il risultato di qualsiasi operazione aritmetica eseguita su due valori di data e ora le cui proprietà DateTime.Kind sono uguali a Utc riflette l'intervallo di tempo effettivo tra i due valori. Allo stesso modo, il confronto tra due valori di data e ora con queste caratteristiche riflette esattamente la relazione tra i due tempi.

  • Il risultato di qualsiasi operazione di confronto o aritmetica eseguita su due valori di data e ora le cui proprietà DateTime.Kind sono uguali a Local o su due valori di data e ora con valori diversi della proprietà DateTime.Kind riflette la differenza di orario tra i due valori.

  • Le operazioni aritmetiche o di confronto sui valori di data e ora locali non considerano se un particolare valore è ambiguo o non valido, né tengono conto dell'effetto di eventuali regole di rettifica risultanti dalla transizione del fuso orario locale da o all'ora legale.

  • Qualsiasi operazione che confronta o calcola la differenza tra l'ora UTC e un'ora locale include nel risultato un intervallo di tempo uguale all'offset del fuso orario locale rispetto all'ora UTC.

  • Qualsiasi operazione che confronta o calcola la differenza tra un'ora non specificata e l'ora UTC o l'ora locale riflette l'orario semplice. Le differenze di fuso orario non vengono considerate e il risultato non riflette l'applicazione di regole di rettifica del fuso orario.

  • Qualsiasi operazione che confronta o calcola la differenza tra due ore non specificate può includere un intervallo sconosciuto che riflette la differenza tra l'ora di due fusi orari diversi.

In molti scenari le differenze di fuso orario non influiscono sui calcoli di data e ora (per informazioni su alcuni di questi, vedere Scelta tra DateTime, DateTimeOffset e TimeZoneInfo) o il contesto dei valori di data e ora definisce il significato delle operazioni di confronto o aritmetiche.

Confronti e operazioni aritmetiche con i valori DateTimeOffset

Un valore DateTimeOffset include non solo una data e un'ora, ma anche un offset che definisce in modo univoco tali data e ora rispetto all'ora UTC. In questo modo è possibile definire l'uguaglianza in modo diverso rispetto ai valori DateTime. Mentre i valori DateTime sono uguali se hanno lo stesso valore di data e ora, i valori DateTimeOffset sono uguali se entrambi si riferiscono allo stesso momento. Ciò rende un valore DateTimeOffset più preciso e meno soggetto a interpretazione quando viene utilizzato nei confronti e nella maggior parte delle operazioni aritmetiche che determinano l'intervallo tra due date e ore. Nell'esempio seguente, che è l'equivalente DateTimeOffset dell'esempio precedente in cui sono stati confrontati i valori DateTime locale e UTC, viene illustrata questa differenza nel comportamento.

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}:{0: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.

In questo esempio, il metodo CompareTo indica che l'ora locale corrente e l'ora UTC corrente sono uguali e la sottrazione dei valori DateTimeOffset indica che la differenza tra i due orari è TimeSpan.Zero.

La limitazione principale dell'utilizzo di valori DateTimeOffset nelle operazioni aritmetiche con date e ora consiste nel fatto che, anche se i valori DateTimeOffset dipendono parzialmente dal fuso orario, in realtà non ne sono completamente dipendenti. Anche se l'offset del valore DateTimeOffset riflette l'offset di un fuso orario rispetto all'ora UTC quando a una variabile DateTimeOffset viene assegnato un valore, l'associazione al fuso orario viene successivamente annullata. Poiché non è più associato direttamente a un'ora identificabile, l'addizione e la sottrazione di intervalli di data e ora non considerano le regole di rettifica di un fuso orario.

A titolo esemplificativo, la transizione all'ora legale nel fuso Ora solare fuso centrale (Stati Uniti) avviene alle 2:00 del 9 marzo 2008. Ciò significa che l'aggiunta di un intervallo di due ore e mezzo all'ora solare fuso centrale di 1:30 del 9 marzo 2008 dovrebbe produrre una data e ora pari alle 5:00 del 9 marzo 2008. Tuttavia, come mostrato nell'esempio, il risultato dell'addizione è 4:00 del 9 marzo 2008. Si noti che il risultato di questa operazione rappresenta il momento corretto, anche se non corrisponde all'ora del fuso orario di interesse (ovvero non include l'offset dal fuso orario previsto).

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

Operazioni aritmetiche con ore nei fusi orari

La classe TimeZoneInfo include diversi metodi di conversione che applicano automaticamente le rettifiche quando convertono le ore da un fuso orario all'altro, tra cui:

Per informazioni dettagliate, vedere Conversione degli orari tra fusi orari.

La classe TimeZoneInfo non fornisce metodi che applicano automaticamente regole di rettifica quando si eseguono operazioni aritmetiche con date e ore. Tuttavia, è possibile ottenere il risultato desiderato convertendo l'ora di un fuso orario in un'ora UTC, eseguendo l'operazione aritmetica ed eseguendo nuovamente la conversione dall'ora UTC all'ora del fuso orario. Per informazioni dettagliate, vedere Procedura: utilizzare fusi orari nell'aritmetica di data e ora.

Ad esempio, il codice seguente è simile al codice precedente, in cui sono state aggiunte due ore e mezzo alle 2:00 del 9 marzo 2008. Tuttavia, poiché in questo caso si converte un'ora solare fuso centrale nell'ora UTC prima di eseguire l'operazione aritmetica con data e ora, e quindi si converte di nuovo il risultato dall'ora UTC all'ora solare fuso centrale, l'ora risultante riflette la transizione del fuso Ora solare fuso centrale all'ora legale.

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

Vedere anche

Attività

Procedura: utilizzare fusi orari nell'aritmetica di data e ora

Altre risorse

Ora e fusi orari