Condividi tramite


Scelta tra DateTime, DateTimeOffset e TimeZoneInfo

Le applicazioni .NET Framework che utilizzano informazioni su data e ora sono molto diverse tra loro e possono utilizzare tali informazioni in svariati modi. Tra gli utilizzi più comuni delle informazioni su data e ora sono inclusi i seguenti:

  • Riflettere solo una data, senza dare rilevanza alle informazioni sull'ora.

  • Riflettere solo un'ora, senza dare rilevanza alle informazioni sulla data.

  • Riflettere una data e un'ora astratte non collegate a un momento e a un luogo specifici; ad esempio, la maggior parte dei negozi di catene internazionali aprono alle 9.00 nei giorni feriali.

  • Recuperare informazioni su data e ora da origini esterne a .NET Framework, in genere dove le informazioni su data e ora vengono archiviate in un tipo di dati semplice.

  • Identificare in modo univoco e inequivocabile uno specifico momento. Alcune applicazioni richiedono che data e ora non siano ambigue solo nel sistema host; altre richiedono che non siano ambigue tra sistemi: in altre parole, una data serializzata in un sistema può essere significativamente deserializzata e utilizzata in un altro sistema in qualsiasi parte del mondo.

  • Mantenere più orari correlati (ad esempio l'ora locale del richiedente e l'ora del server di ricezione di una richiesta Web).

  • Eseguire operazioni aritmetiche con date e ore, possibilmente con un risultato che identifichi in modo univoco e inequivocabile uno specifico momento.

In .NET Framework sono inclusi i tipi DateTime, DateTimeOffset e TimeZoneInfo, tutti utilizzabili per compilare applicazioni che funzionano con date e ore.

NotaNota

In questo argomento non viene trattato un quarto tipo, TimeZone, perché la relativa funzionalità è quasi completamente incorporata nella classe TimeZoneInfo.Quando possibile, gli sviluppatori dovrebbero preferire l'utilizzo della classe TimeZoneInfo alla classe TimeZone.

Struttura DateTime

Un valore DateTime definisce una particolare data e ora. A partire dalla versione 2.0 di .NET Framework, è inclusa una proprietà Kind che fornisce informazioni limitate sul fuso orario a cui appartengono la data e l'ora specificate. Il valore DateTimeKind restituito dalla proprietà Kind indica se il valore DateTime rappresenta l'ora locale (DateTimeKind.Local), l'ora UTC (Coordinated Universal Time) (DateTimeKind.Utc) o un'ora non specificata (DateTimeKind.Unspecified).

La struttura DateTime è adatta per applicazioni che:

  • Utilizzano solo date.

  • Utilizzano solo ore.

  • Utilizzano date e ore astratte.

  • Recuperano informazioni su data e ora da origini esterne a .NET Framework, ad esempio database SQL. In genere, queste origini archiviano informazioni su data e ora in un formato semplice, compatibile con la struttura DateTime.

  • Eseguono operazioni aritmetiche con date e ore, ma con un interesse preminente per il risultato generale. Ad esempio, in un'operazione di addizione che aggiunge sei mesi a una particolare data e ora, spesso non è importante se nel risultato si tiene conto dell'ora legale.

A meno che un particolare valore DateTime rappresenti l'ora UTC, il valore di data e ora specificato è spesso ambiguo o limitato nella portabilità. Ad esempio, se un valore DateTime rappresenta l'ora locale, è portabile all'interno del fuso orario locale; cioè, se il valore viene deserializzato in un altro sistema nello stesso fuso orario, quel valore identifica ancora inequivocabilmente uno specifico momento. Al di fuori del fuso orario locale, quel valore DateTime può avere più interpretazioni. Se la proprietà Kind del valore è DateTimeKind.Unspecified, il valore è ancora meno portabile, poiché è ambiguo all'interno dello stesso fuso orario e probabilmente anche nello stesso sistema in cui è stato inizialmente serializzato. Solo se un valore DateTime rappresenta l'ora UTC può identificare inequivocabilmente un momento specifico, indipendentemente dal sistema o dal fuso orario nel quale viene utilizzato.

Nota importanteImportante

Quando si salvano o si condividono i dati DateTime, dovrebbe essere utilizzata l'ora UTC e la proprietà Kind del valore DateTime dovrebbe essere impostata su DateTimeKind.Utc.

Struttura DateTimeOffset

La struttura DateTimeOffset rappresenta un valore di data e ora con un offset che indica di quanto il valore differisce dall'ora UTC. Pertanto, il valore identifica sempre inequivocabilmente uno specifico momento.

Anche se il tipo DateTimeOffset include la maggior parte delle funzionalità del tipo DateTime, non deve sostituire il tipo DateTime nello sviluppo di applicazioni. La struttura è invece adatta per applicazioni che:

  • Identificano in modo univoco e inequivocabile uno specifico momento. Il tipo DateTimeOffset può essere utilizzato per definire inequivocabilmente il significato di "questo momento", registrare le ore delle transazioni e degli eventi di sistema o delle applicazioni, nonché registrare le ore di creazione e modifica dei file.

  • Eseguono operazioni aritmetiche generiche con date e ore.

  • Mantengono più orari correlati, purché archiviati come due valori separati o due membri di una struttura.

NotaNota

Questi utilizzi per i valori DateTimeOffset sono molto più comuni di quelli per i valori DateTime.Di conseguenza, DateTimeOffset deve essere considerato il tipo di data e ora predefinito per lo sviluppo di applicazioni.

Un valore DateTimeOffset non è collegato a un particolare fuso orario, ma può originare da una varietà di fusi orari. Per illustrare questo concetto, nell'esempio seguente sono elencati i fusi orari ai quali una serie di valori DateTimeOffset (inclusa l'ora solare Pacifico (Stati Uniti) locale) può appartenere.

Imports System.Collections.ObjectModel

Module TimeOffsets
   Public Sub Main()
      Dim thisTime As DateTimeOffset 

      thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
      ShowPossibleTimeZones(thisTime) 

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))  
      ShowPossibleTimeZones(thisTime)

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
      ShowPossibleTimeZones(thisTime)
   End Sub

   Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
      Dim offset As TimeSpan = offsetTime.Offset
      Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

      Console.WriteLine("{0} could belong to the following time zones:", _
                        offsetTime.ToString())
      ' Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones()     
      ' Iterate time zones
      For Each timeZone As TimeZoneInfo In timeZones
         ' Compare offset with offset for that date in that time zone
         If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
            Console.WriteLine("   {0}", timeZone.DisplayName)
         End If   
      Next
      Console.WriteLine()
   End Sub
End Module
' This example displays the following output to the console:
'       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
'          (GMT-07:00) Arizona
'          (GMT-08:00) Pacific Time (US & Canada)
'          (GMT-08:00) Tijuana, Baja California
'       
'       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
'          (GMT-06:00) Central America
'          (GMT-06:00) Central Time (US & Canada)
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
'          (GMT-06:00) Saskatchewan
'       
'       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
'          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
'          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
'          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
'          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
'          (GMT+01:00) West Central Africa
using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;

      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));  
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;

      Console.WriteLine("{0} could belong to the following time zones:", 
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();     
      // Iterate time zones 
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   } 
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//       
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//       
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa

L'output mostra che ogni valore di data e ora in questo esempio può appartenere ad almeno tre fusi orari diversi. Il valore DateTimeOffset di 6/10/2007 mostra che se un valore di data e ora rappresenta un'ora legale, l'offset dall'ora UTC non corrisponde necessariamente all'offset UTC di base del fuso orario di origine né all'offset dall'ora UTC trovato nel nome visualizzato. Questo esempio dimostra che, poiché un singolo valore DateTimeOffset non è strettamente accoppiato al proprio fuso orario, non può riflettere la transizione nell'ora legale e dall'ora legale di un fuso orario. Questa situazione può essere particolarmente problematica quando si utilizzano le operazioni aritmetiche con date e ore per modificare un valore DateTimeOffset. Per una discussione su come eseguire operazioni aritmetiche con date e ore in un modo che prenda in considerazione le regole di rettifica di un fuso orario, vedere Esecuzione di operazioni aritmetiche con date e ore.

Classe TimeZoneInfo

La classe TimeZoneInfo rappresenta qualsiasi fuso orario terrestre e consente la conversione di qualsiasi data e ora di un fuso orario nell'equivalente di un altro fuso orario. La classe TimeZoneInfo rende possibile utilizzare date e ore in modo che qualsiasi valore di data e ora identifichi inequivocabilmente uno specifico momento. La classe TimeZoneInfo è anche estendibile. Anche se dipende dalle informazioni sui fusi orari fornite per i sistemi Windows e definite nel Registro di sistema, supporta la creazione di fusi orari personalizzati, nonché la serializzazione e deserializzazione delle informazioni sui fusi orari.

In alcuni casi, per usufruire completamente dei vantaggi offerti dalla classe TimeZoneInfo è necessaria un'attività di sviluppo aggiuntiva. Innanzi tutto, i valori di data e ora non sono strettamente accoppiati con i fusi orari ai quali appartengono. Di conseguenza, a meno che l'applicazione fornisca un meccanismo per collegare una data e ora al fuso orario associato, è facile che risulti annullata l'associazione di un particolare valore di data e ora al proprio fuso orario. Un metodo per collegare queste informazioni consiste nel definire una classe o una struttura che contiene sia il valore di data e ora sia l'oggetto fuso orario associato. In secondo luogo, in Windows XP e nelle versioni precedenti di Windows non esiste un vero supporto per le informazioni cronologiche sui fusi orari e in Windows Vista il supporto è limitato. Le applicazioni progettate per gestire cronologie di date e ore devono fare uso massiccio dei fusi orari personalizzati.

In .NET Framework è possibile usufruire dei vantaggi del supporto relativo ai fusi orari solo se il fuso orario a cui appartiene un valore di data e ora è noto quando viene creata un'istanza dell'oggetto data e ora specificato. Questa circostanza non è frequente, particolarmente in applicazioni Web o di rete.

Vedere anche

Altre risorse

Date, ora e fusi orari