Condividi tramite


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

In genere, quando si esegue l'aritmetica di data e ora utilizzando i valori DateTime o DateTimeOffset, il risultato non riflette le regole di regolazione dei fusi orari. Questo vale anche quando il fuso orario del valore di data e ora è chiaramente identificabile, ad esempio quando la proprietà Kind è impostata su Local. In questo argomento viene illustrato come eseguire operazioni aritmetiche su valori di data e ora appartenenti a un determinato fuso orario. I risultati delle operazioni aritmetiche rifletteranno le regole di regolazione del fuso orario.

Per applicare le regole di regolazione all'aritmetica di data e ora

  1. Implementare un metodo in base al quale un valore di data e ora è strettamente collegato al fuso orario al quale appartiene. Ad esempio, dichiarare una struttura che includa il valore di data e ora e il relativo fuso orario. Nell'esempio seguente viene utilizzato tale approccio per collegare un valore DateTime al relativo fuso orario.

    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
       Dim TimeZone As TimeZoneInfo
       Dim Time As Date
    End Structure
    
    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
       TimeZoneInfo TimeZone;
       DateTime Time;
    }
    
  2. Convertire un'ora nell'ora UTC (Coordinated Universal Time) chiamando il metodo ConvertTimeToUtc o il metodo ConvertTime.

  3. Eseguire l'operazione aritmetica sull'ora UTC.

  4. Convertire l'ora dall'ora UTC al fuso orario dell'ora originale chiamando il metodo TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo).

Esempio

Nell'esempio seguente vengono aggiunti due ore e trenta minuti al 9 marzo 2008, 1.30 Ora solare fuso centrale. La transizione del fuso orario a ora legale si verifica trenta minuti dopo, alle 2.00 del 9 marzo 2008. Poiché nell'esempio vengono seguiti i quattro passaggi riportati nella sezione precedente, l'orario corretto risultante corrisponderà alle 5.00. del 9 marzo 2008.

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
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);
      }
   }
}

L'associazione di entrambi i valori DateTime e DateTimeOffset a un fuso orario al quale potrebbero appartenere viene annullata. Per eseguire l'aritmetica di data e ora in modo da applicare automaticamente le regole di regolazione di un fuso orario, è necessario che il fuso orario a cui appartiene il valore di data e ora sia immediatamente identificabile, ovvero che la data e ora e il relativo fuso orario associato siano strettamente collegati. Sono disponibili diversi modi per eseguire tale operazione, tra cui:

  • Presupporre che tutti gli orari utilizzati in un'applicazione appartengano a un determinato fuso orario. Sebbene adatto in alcuni casi, questo approccio ha una flessibilità limitata e talvolta anche una portabilità limitata.

  • Definire un tipo in base al quale una data e ora siano strettamente collegate al relativo fuso orario associato includendo entrambi i valori come campi del tipo. Questo approccio viene utilizzato nell'esempio di codice definendo una struttura per archiviare la data e ora e il fuso orario in due campi membro.

Nell'esempio viene illustrato come eseguire operazioni aritmetiche sui valori DateTime in modo da applicare le regole di regolazione del fuso orario al risultato. È possibile eventualmente utilizzare i valori DateTimeOffset altrettanto facilmente. Nell'esempio seguente viene illustrato come modificare il codice dell'esempio originale per l'utilizzo di DateTimeOffset anziché dei valori DateTime.

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
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);
      }
   }
}

Notare che se questa somma viene eseguita semplicemente sul valore DateTimeOffset senza prima convertirlo nell'ora UTC, il risultato rifletterà il momento esatto mentre l'offset relativo non rifletterà quello del fuso orario definito per tale orario.

Compilazione del codice

Per questo esempio è necessario:

  • Aggiungere un riferimento a System.Core.dll al progetto.

  • Importare lo spazio dei nomi System con l'istruzione using (richiesto nel codice C#).

Vedere anche

Concetti

Esecuzione di operazioni aritmetiche con date e ore

Altre risorse

Date, ora e fusi orari