Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È sempre più importante per qualsiasi applicazione che funzioni con date e ore per gestire le differenze tra fusi orari. Un'applicazione non può più presupporre che tutti i tempi possano essere espressi nell'ora locale, ovvero il tempo disponibile dalla struttura DateTime. Ad esempio, una pagina Web che visualizza l'ora corrente nella parte orientale degli Stati Uniti non avrà credibilità per un cliente nell'Asia orientale. Questo articolo illustra come convertire gli orari da un fuso orario a un altro e convertire DateTimeOffset valori con riconoscimento limitato del fuso orario.
Conversione in ora universale coordinata
L'ora UTC (Coordinated Universal Time) è uno standard ora atomico ad alta precisione. I fusi orari del mondo sono espressi come offset positivi o negativi rispetto all'ora UTC. Di conseguenza, l'ora UTC fornisce un'ora indipendente dal fuso orario. L'uso dell'ora UTC è consigliato quando la portabilità di una data e dell'ora nei computer è importante. Per informazioni dettagliate e altre procedure consigliate per l'uso di date e ore, vedere Procedure consigliate per la codifica con DateTime in .NET Framework. La conversione di singoli fusi orari in utc semplifica i confronti temporali.
Nota
È anche possibile serializzare una struttura DateTimeOffset per rappresentare un singolo punto nel tempo senza ambiguità. Poiché DateTimeOffset oggetti archiviano un valore di data e ora insieme all'offset rispetto all'ora UTC, rappresentano sempre un determinato punto nel tempo rispetto all'ora UTC.
Il modo più semplice per convertire un orario a UTC consiste nel chiamare il metodo static (Shared in Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime). La conversione esatta eseguita dal metodo dipende dal valore della proprietà Kind del parametro dateTime, come illustrato nella tabella seguente:
DateTime.Kind |
Conversione |
|---|---|
DateTimeKind.Local |
Converte l'ora locale in utc. |
DateTimeKind.Unspecified |
Si presuppone che il parametro dateTime sia l'ora locale e converta l'ora locale in utc. |
DateTimeKind.Utc |
Restituisce il parametro dateTime invariato. |
Il codice seguente converte l'ora locale corrente in UTC e visualizza il risultato nella console:
DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
TimeZoneInfo.ConvertTimeToUtc(dateNow))
Se il valore di data e ora non rappresenta l'ora locale o l'ora UTC, è probabile che il metodo ToUniversalTime restituisca un risultato errato. Tuttavia, è possibile utilizzare il metodo TimeZoneInfo.ConvertTimeToUtc per convertire la data e l'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. Il codice seguente usa il metodo TimeZoneInfo.ConvertTimeToUtc per convertire l'ora solare orientale in utc:
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 {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
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
Il metodo TimeZoneInfo.ConvertTimeToUtc genera un ArgumentException se la proprietà Kind dell'oggetto DateTime e il fuso orario non corrispondono. Una mancata corrispondenza si verifica se la proprietà Kind è DateTimeKind.Local ma l'oggetto TimeZoneInfo non rappresenta il fuso orario locale o se la proprietà Kind è DateTimeKind.Utc ma l'oggetto TimeZoneInfo non è uguale a TimeZoneInfo.Utc.
Tutti questi metodi accettano DateTime valori come parametri e restituiscono un valore DateTime. Per DateTimeOffset valori, la struttura DateTimeOffset ha un metodo di istanza ToUniversalTime che converte la data e l'ora dell'istanza corrente in formato UTC. Nell'esempio seguente viene chiamato il metodo ToUniversalTime per convertire un'ora locale e diverse altre volte in formato UTC:
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: {localTime}");
Console.WriteLine();
// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine($"Other time: {otherTime}");
Console.WriteLine($"{localTime} = {otherTime}: {localTime.Equals(otherTime)}");
Console.WriteLine($"{localTime} exactly equals {otherTime}: {localTime.EqualsExact(otherTime)}");
Console.WriteLine();
// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine($"Universal time: {universalTime}");
Console.WriteLine($"{otherTime} = {universalTime}: {universalTime.Equals(otherTime)}");
Console.WriteLine($"{otherTime} exactly equals {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
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
Conversione dell'ora UTC in un fuso orario designato
Per convertire l'ora UTC nell'ora locale, vedere la sezione Conversione dell'ora UTC all'ora locale riportata di seguito. Per convertire l'ora UTC nell'ora in qualsiasi fuso orario designato, chiamare il metodo ConvertTimeFromUtc. Il metodo accetta due parametri:
Ora UTC da convertire. Deve essere un valore DateTime la cui proprietà Kind è impostata su
UnspecifiedoUtc.Fuso orario in cui convertire l'ora UTC.
Il codice seguente converte l'ora UTC in ora solare centrale:
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.");
}
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
Conversione dell'ora UTC all'ora locale
Per convertire l'ora UTC nell'ora locale, chiamare il metodo ToLocalTime dell'oggetto DateTime la cui ora si desidera convertire. Il comportamento esatto del metodo dipende dal valore della proprietà Kind dell'oggetto, come illustrato nella tabella seguente:
DateTime.Kind |
Conversione |
|---|---|
DateTimeKind.Local |
Restituisce il valore DateTime invariato. |
DateTimeKind.Unspecified |
Si presuppone che il valore DateTime sia UTC e converta l'ora UTC nell'ora locale. |
DateTimeKind.Utc |
Converte il valore DateTime in ora locale. |
Nota
Il metodo TimeZone.ToLocalTime si comporta in modo identico al metodo DateTime.ToLocalTime. Per eseguire la conversione è necessario un singolo parametro, ovvero il valore di data e ora.
È possibile anche convertire l'ora in qualsiasi fuso orario designato nell'ora locale usando il metodo static (Shared in Visual Basic) TimeZoneInfo.ConvertTime. Questa tecnica è descritta nella sezione successiva.
Conversione tra due fusi orari
È possibile eseguire la conversione tra due fusi orari usando 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
TimeZoneInfoche rappresenta il fuso orario del valore di data e ora e un oggettoTimeZoneInfoche 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 per convertire e l'oggetto TimeZoneInfo o l'identificatore del fuso orario che rappresenta il relativo fuso orario corrispondono l'uno all'altro. In caso contrario, verrà generata un'eccezione ArgumentException. Ad esempio, se 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. Viene generata anche un'eccezione se l'identificatore passato come parametro al metodo non è uguale a TimeZoneInfo.Local.Id.
L'esempio seguente usa il metodo ConvertTime per eseguire la conversione dall'ora solare hawaiana all'ora locale:
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.");
}
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
Conversione dei valori DateTimeOffset
I valori di data e ora rappresentati dagli oggetti DateTimeOffset non considerano completamente il fuso orario perché l'oggetto è dissociato dal suo fuso orario al momento della sua istanziazione. Tuttavia, in molti casi, un'applicazione deve semplicemente convertire una data e un'ora in base a due offset diversi rispetto all'ora UTC anziché all'ora in determinati fusi orari. Per eseguire questa conversione, è possibile chiamare il metodo di ToOffset dell'istanza corrente. Il parametro unico del metodo è l'offset del nuovo valore di data e ora che il metodo restituirà.
Ad esempio, se la data e l'ora di una richiesta utente per una pagina Web è nota e serializzata come stringa nel formato MM/gg/aaaa hh:mm:ss zzzz, il metodo ReturnTimeOnServer seguente converte questo valore di data e ora nella data e ora nel server Web:
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;
}
}
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
Se il metodo passa la stringa "9/1/2007 5:32:07 -05:00", che rappresenta la data e l'ora in un fuso orario cinque ore precedenti all'ora UTC, restituisce "9/1/2007 3:32:07 AM -07:00" per un server che si trova nel fuso orario standard degli Stati Uniti.
La classe TimeZoneInfo include anche un sovraccarico del metodo TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) che esegue conversioni di fuso orario con valori ToOffset(TimeSpan). 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 nell'esempio precedente può essere riscritto come segue per chiamare il metodo ConvertTime(DateTimeOffset, TimeZoneInfo).
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;
}
}
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