Conversione degli orari tra fusi orari
La gestione delle differenze tra fusi orari sta divenendo sempre più importante per le applicazioni che utilizzano date e ore. Non è più possibile presupporre che tutti gli orari possano essere espressi su base locale, ovvero in base all'orario disponibile dalla struttura DateTime. Ad esempio, una pagina Web che visualizza l'orario corrente della parte orientale degli Stati Uniti risulterà non attendibile per un cliente dell'Asia orientale. In questo argomento viene illustrato come convertire gli orari da un fuso orario all'altro, nonché come convertire i valori DateTimeOffset che dipendono in parte dal fuso orario.
Conversione nel formato UTC
UTC (Coordinated Universal Time) è uno standard di alta precisione basato sul tempo atomico. I fusi orari del mondo sono espressi come offset positivi o negativi dall'ora UTC. L'orario espresso in UTC è quindi indipendente dal fuso orario. L'utilizzo dell'ora UTC è consigliato quando la portabilità di data e ora tra i computer è importante. Per informazioni dettagliate e altre procedure consigliate sull'utilizzo di date e ore, vedere Coding Best Practices Using DateTime in the .NET Framework (informazioni in lingua inglese). La conversione di singoli fusi orari in ore UTC semplifica i confronti tra gli orari.
Nota |
---|
È inoltre possibile serializzare una struttura DateTimeOffset per rappresentare in modo non ambiguo un determinato momento.Poiché gli oggetti DateTimeOffset archiviano un valore di data e ora insieme all'offset dall'ora UTC, rappresentano sempre un determinato momento in relazione all'ora UTC. |
Il modo più semplice per convertire un orario in ora UTC è chiamare il metodo TimeZoneInfo.ConvertTimeToUtc(DateTime) static, ovvero Shared in Visual Basic. Il tipo specifico di conversione eseguita dal metodo dipende dal valore della proprietà Kind del parametro dateTime, come mostrato nella tabella seguente.
Proprietà DateTime.Kind |
Conversion |
---|---|
Converte l'ora locale in ora UTC. |
|
Presuppone che il parametro dateTime sia l'ora locale e converte l'ora locale in ora UTC. |
|
Restituisce il parametro dateTime invariato. |
Nel codice seguente l'ora locale corrente viene convertita in ora UTC e il risultato viene visualizzato nella console.
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
TimeZoneInfo.ConvertTimeToUtc(dateNow))
DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.",
TimeZoneInfo.ConvertTimeToUtc(dateNow));
Nota |
---|
Il metodo TimeZoneInfo.ConvertTimeToUtc(DateTime) non comporta necessariamente risultati identici a quelli forniti dai metodi TimeZone.ToUniversalTime e DateTime.ToUniversalTime.Se il fuso orario locale del sistema host comprende più regole di modifica, il metodo TimeZoneInfo.ConvertTimeToUtc(DateTime) applica la regola appropriata a una data e un'ora specifici.Gli altri due metodi vengono sempre applicati alla regola di modifica più recente. |
Se il valore di data e ora non rappresenta l'ora locale o l'ora UTC, il metodo ToUniversalTime restituirà probabilmente un risultato errato. È tuttavia possibile utilizzare il metodo TimeZoneInfo.ConvertTimeToUtc per convertire la data e ora da un fuso orario specificato. Per informazioni dettagliate sul recupero di un oggetto TimeZoneInfo che rappresenta il fuso orario di destinazione, vedere Ricerca dei fusi orari definiti in un sistema locale. Nel codice seguente viene utilizzato il metodo TimeZoneInfo.ConvertTimeToUtc per convertire l'ora solare fuso orientale in ora UTC.
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
Console.WriteLine("The date and time are {0} UTC.", _
TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
Console.WriteLine("Unable to find the {0} zone in the registry.", _
easternZoneId)
Catch e As InvalidTimeZoneException
Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
easternZoneId)
End Try
DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
Console.WriteLine("The date and time are {0} UTC.",
TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone));
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to find the {0} zone in the registry.",
easternZoneId);
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the {0} zone has been corrupted.",
easternZoneId);
}
Notare che questo metodo genera un'eccezione ArgumentException se la proprietà Kind dell'oggetto DateTime e il fuso orario non corrispondono. Una mancata corrispondenza viene rilevata se la proprietà Kind è DateTimeKind.Local ma l'oggetto TimeZoneInfo non rappresenta il fuso orario locale oppure se la proprietà Kind è DateTimeKind.Utc ma l'oggetto TimeZoneInfo non è uguale a DateTimeKind.Utc.
Tutti questi metodi accettano valori DateTime come parametri e restituiscono un valore DateTime. Per i valori DateTimeOffset, la struttura DateTimeOffset presenta un metodo di istanza ToUniversalTime che converte la data e ora dell'istanza corrente in ora UTC. Nell'esempio seguente viene chiamato il metodo ToUniversalTime per convertire l'ora locale e diversi altri orari nell'ora UTC (Coordinated Universal Time).
Dim localTime, otherTime, universalTime As DateTimeOffset
' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()
' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
localTime, otherTime, _
localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
localTime, otherTime, _
localTime.EqualsExact(otherTime))
Console.WriteLine()
' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
otherTime, universalTime, _
universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
otherTime, universalTime, _
universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
' Local time: 6/15/2007 12:00:00 PM -07:00
'
' Other time: 6/15/2007 7:00:00 PM +00:00
' 6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
' 6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'
' Universal time: 6/15/2007 7:00:00 PM +00:00
' 6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
' 6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
DateTimeOffset localTime, otherTime, universalTime;
// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();
// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}",
localTime, otherTime,
localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
localTime, otherTime,
localTime.EqualsExact(otherTime));
Console.WriteLine();
// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}",
otherTime, universalTime,
universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
otherTime, universalTime,
universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
// Local time: 6/15/2007 12:00:00 PM -07:00
//
// Other time: 6/15/2007 7:00:00 PM +00:00
// 6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
// 6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
// Universal time: 6/15/2007 7:00:00 PM +00:00
// 6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
// 6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Conversione dell'ora UTC in un determinato fuso orario
Per convertire l'ora UTC nell'ora locale, vedere la sezione "Conversione dell'ora UTC nell'ora locale" riportata di seguito. Per convertire l'ora UTC nell'ora di un determinato fuso orario, chiamare il metodo ConvertTimeFromUtc. Questo metodo accetta due parametri:
L'ora UTC da convertire. Deve essere un valore DateTime la cui proprietà Kind è impostata su DateTimeKind.Utc o DateTimeKind.Unspecified.
Il fuso orario nel quale convertire l'ora UTC.
Nel codice seguente l'ora UTC viene convertita nell'ora solare fuso centrale.
Dim timeUtc As Date = Date.UtcNow
Try
Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
Console.WriteLine("The date and time are {0} {1}.", _
cstTime, _
IIf(cstZone.IsDaylightSavingTime(cstTime), _
cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try
DateTime timeUtc = DateTime.UtcNow;
try
{
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
Console.WriteLine("The date and time are {0} {1}.",
cstTime,
cstZone.IsDaylightSavingTime(cstTime) ?
cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the Central STandard Time zone has been corrupted.");
}
Conversione dell'ora UTC nell'ora locale
Per convertire l'ora UTC nell'ora locale, chiamare il metodo ToLocalTime dell'oggetto DateTime di cui si desidera convertire l'orario. Il comportamento esatto del metodo dipende dal valore della proprietà Kind dell'oggetto, come illustrato nella tabella riportata di seguito.
Proprietà DateTime.Kind |
Conversion |
---|---|
DateTimeKind.Local |
Restituisce il valore DateTime invariato. |
DateTimeKind.Unspecified |
Presuppone che il valore DateTime sia UTC e converte l'ora UTC nell'ora locale. |
DateTimeKind.Utc |
Converte il valore DateTime nell'ora locale. |
Nota Il metodo TimeZone.ToLocalTime si comporta in modo identico al metodo DateTime.ToLocalTime. Accetta un solo parametro, ovvero il valore di data e ora da convertire.
È inoltre possibile convertire l'ora di un determinato fuso orario nell'ora locale utilizzando il metodo TimeZoneInfo.ConvertTime static (Shared in Visual Basic). Questa tecnica viene illustrata nella sezione seguente.
Conversione tra due fusi orari
È possibile eseguire la conversione tra due fusi orari utilizzando uno dei due metodi seguenti static (Shared in Visual Basic) della classe TimeZoneInfo:
-
I parametri di questo metodo sono il valore di data e ora da convertire, un oggetto TimeZoneInfo che rappresenta il fuso orario del valore di data e ora e un oggetto TimeZoneInfo che rappresenta il fuso orario in cui convertire il valore di data e ora.
-
I parametri di questo metodo sono il valore di data e ora da convertire, l'identificatore del fuso orario del valore di data e ora e l'identificatore del fuso orario in cui convertire il valore di data e ora.
Entrambi i metodi richiedono che la proprietà Kind del valore di data e ora da convertire e l'oggetto TimeZoneInfo o l'identificatore del fuso orario che rappresenta il relativo fuso orario corrispondano tra loro. In caso contrario, verrà generata un'eccezione ArgumentException. Se, ad esempio, la proprietà Kind del valore di data e ora è DateTimeKind.Local, viene generata un'eccezione se l'oggetto TimeZoneInfo passato come parametro al metodo non è uguale a TimeZoneInfo.Local. Un'eccezione viene inoltre generata se l'identificatore passato come parametro al metodo non è uguale a TimeZoneInfo.Local.Id.
Nell'esempio seguente viene utilizzato il metodo ConvertTime per eseguire la conversione dall'ora solare Hawaii all'ora locale.
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
Console.WriteLine("{0} {1} is {2} local time.", _
hwTime, _
IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try
DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
Console.WriteLine("{0} {1} is {2} local time.",
hwTime,
hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the Hawaiian STandard Time zone has been corrupted.");
}
Conversione dei valori DateTimeOffset
I valori di data e ora rappresentati dagli oggetti DateTimeOffset non dipendono completamente dal fuso orario poiché è stata annullata l'associazione dell'oggetto al relativo fuso orario durante la creazione di un'istanza di tale oggetto. In molti casi è tuttavia necessario convertire semplicemente una data e ora in base a due diversi offset dall'ora UTC anziché in base all'ora di determinati fusi orari. Per eseguire questa conversione, è possibile chiamare il metodo ToOffset dell'istanza corrente. L'unico parametro del metodo è l'offset del nuovo valore di data e ora restituito dal metodo.
Se, ad esempio, la data e ora di una richiesta dell'utente per una pagina Web è nota e serializzata come stringa nel formato MM/dd/yyyy hh:mm:ss zzzz, il metodo ReturnTimeOnServer seguente converte questo valore di data e ora nella data e ora del server Web.
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
Dim format As String = "M/d/yyyy H:m:s zzz"
Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)
Try
Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
Return serverTime
Catch e As FormatException
Return DateTimeOffset.MinValue
End Try
End Function
public DateTimeOffset ReturnTimeOnServer(string clientString)
{
string format = @"M/d/yyyy H:m:s zzz";
TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);
try
{
DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
return serverTime;
}
catch (FormatException)
{
return DateTimeOffset.MinValue;
}
}
Se al metodo viene passata la stringa "9/1/2007 5.32.07 -05.00" che rappresenta la data e l'ora in un fuso orario indietro di cinque ore rispetto all'ora UTC, viene restituito 9/1/2007 3.32.07 AM -07.00 per un server situato nel fuso Ora solare Pacifico (Stati Uniti).
La classe TimeZoneInfo include anche un overload del metodo TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) che esegue le conversioni del fuso orario con i valori DateTimeOffset. I parametri del metodo sono un valore DateTimeOffset e un riferimento al fuso orario in cui convertire l'ora. La chiamata al metodo restituisce un valore DateTimeOffset. Ad esempio, il metodo ReturnTimeOnServer dell'esempio precedente potrebbe essere riscritto come segue per chiamare il metodo ConvertTime(DateTimeOffset, TimeZoneInfo).
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
Dim format As String = "M/d/yyyy H:m:s zzz"
Try
Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
Return serverTime
Catch e As FormatException
Return DateTimeOffset.MinValue
End Try
End Function
public DateTimeOffset ReturnTimeOnServer(string clientString)
{
string format = @"M/d/yyyy H:m:s zzz";
try
{
DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
CultureInfo.InvariantCulture);
DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
TimeZoneInfo.Local);
return serverTime;
}
catch (FormatException)
{
return DateTimeOffset.MinValue;
}
}
Vedere anche
Riferimenti
Concetti
Ricerca dei fusi orari definiti in un sistema locale