Conversione degli orari tra fusi orari

La gestione delle differenze tra fusi orari sta divenendo sempre più importante per le applicazioni che usano date e ore. Un'applicazione non può più presupporre che tutte le ore possano essere espresse nell'ora locale, ovvero l'ora disponibile dalla DateTime struttura . 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 a un altro, nonché come convertire valori con riconoscimento DateTimeOffset del fuso orario limitato.

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 rispetto all'ora UTC. L'ora espressa in UTC è quindi indipendente dal fuso orario. L'uso dell'ora UTC è consigliato quando la portabilità di data e ora tra i computer è importante. Per informazioni dettagliate e altre procedure consigliate sull'uso di date e ore, vedere Procedure consigliate per la scrittura del codice con DateTime nel.NET Framework . La conversione di singoli fusi orari in UTC semplifica i confronti di ora.

Nota

È anche possibile serializzare una struttura per rappresentare in modo univoco DateTimeOffset un singolo punto nel tempo. Poiché gli oggetti archiviano un valore di data e ora insieme al relativo offset dall'ora UTC, rappresentano sempre un particolare punto DateTimeOffset nel tempo in relazione all'ora UTC.

Il modo più semplice per convertire un'ora in formato UTC è chiamare il metodo static ( Shared in TimeZoneInfo.ConvertTimeToUtc(DateTime) Visual Basic). La conversione esatta eseguita dal metodo dipende dal valore della proprietà del dateTime Kind parametro, come illustrato nella tabella seguente.

DateTime.Kind Conversione
DateTimeKind.Local Converte l'ora locale in ora UTC.
DateTimeKind.Unspecified Presuppone che il parametro dateTime sia l'ora locale e converte l'ora locale in ora UTC.
DateTimeKind.Utc Restituisce il parametro dateTime invariato.

Il codice seguente converte l'ora locale corrente in ora UTC e visualizza il risultato nella console.

DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.",
                   TimeZoneInfo.ConvertTimeToUtc(dateNow));
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, il metodo restituirà probabilmente ToUniversalTime un risultato eroso. Tuttavia, è possibile usare il TimeZoneInfo.ConvertTimeToUtc metodo per convertire la data e l'ora da un fuso orario specificato. Per informazioni dettagliate sul recupero di un oggetto che rappresenta il fuso orario di destinazione, vedere Ricerca dei fusi orari definiti TimeZoneInfo in un sistema locale. Nel codice seguente viene utilizzato il TimeZoneInfo.ConvertTimeToUtc metodo per convertire l'ora solare fuso orientale in ora 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 {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);
}
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

Si noti che questo metodo genera ArgumentException un'eccezione se DateTime la proprietà dell'oggetto e il fuso orario non sono Kind corrispondenti. Una mancata corrispondenza si verifica se la proprietà è ma l'oggetto non rappresenta il fuso orario locale oppure se la proprietà è ma l'oggetto Kind non è uguale a DateTimeKind.Local TimeZoneInfo Kind DateTimeKind.Utc TimeZoneInfo TimeZoneInfo.Utc .

Tutti questi metodi accettano DateTime valori come parametri e restituiscono un DateTime valore. Per i valori, la struttura dispone di un metodo di istanza che converte la data e DateTimeOffset DateTimeOffset l'ora ToUniversalTime dell'istanza corrente in UTC. Nell'esempio seguente viene chiamato il metodo per convertire un'ora locale e diverse altre volte ToUniversalTime in Coordinated Universal Time (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: {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
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 determinato fuso orario

Per convertire l'ora UTC in ora locale, vedere la sezione "Conversione dell'ora UTC in ora locale" che segue. Per convertire l'ora UTC nell'ora in qualsiasi fuso orario designato, chiamare il ConvertTimeFromUtc metodo . Il metodo accetta due parametri:

  • L'ora UTC da convertire. Deve essere un DateTime valore la cui proprietà è Kind impostata su o Unspecified Utc .

  • Il fuso orario nel quale convertire l'ora UTC.

Nel codice seguente l'ora UTC viene convertita nell'ora solare fuso 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 nell'ora locale

Per convertire l'ora UTC nell'ora locale, chiamare ToLocalTime il metodo DateTime dell'oggetto di cui si vuole convertire l'ora. Il comportamento esatto del metodo dipende dal valore della proprietà dell'oggetto, Kind come illustrato nella tabella seguente.

DateTime.Kind Conversione
DateTimeKind.Local Restituisce il DateTime valore invariato.
DateTimeKind.Unspecified Presuppone che il valore DateTime sia UTC e converte l'ora UTC nell'ora locale.
DateTimeKind.Utc Converte il DateTime valore nell'ora locale.

Nota

Il TimeZone.ToLocalTime metodo si comporta in modo identico al metodo DateTime.ToLocalTime . Accetta un singolo parametro, ovvero il valore di data e ora da convertire.

È anche possibile convertire l'ora in qualsiasi fuso orario designato in ora locale usando il metodo static ( Shared in TimeZoneInfo.ConvertTime Visual Basic). Questa tecnica viene illustrata nella sezione successiva.

Conversione tra due fusi orari

È possibile eseguire la conversione tra due fusi orari qualsiasi usando uno dei due metodi static ( Shared in Visual Basic) seguenti della classe TimeZoneInfo :

  • ConvertTime

    I parametri di questo metodo sono il valore di data e ora da convertire, un oggetto che rappresenta il fuso orario del valore di data e ora e un oggetto che rappresenta il fuso orario in cui convertire il valore di data e TimeZoneInfo TimeZoneInfo ora.

  • ConvertTimeBySystemTimeZoneId

    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à del valore di data e ora da convertire e l'identificatore dell'oggetto o del fuso orario che rappresenta il fuso orario Kind TimeZoneInfo corrispondano tra loro. In caso contrario, verrà generata un'eccezione ArgumentException. Ad esempio, se la proprietà del valore di data e ora è , viene generata un'eccezione se l'oggetto passato come parametro al metodo Kind non è uguale a DateTimeKind.Local TimeZoneInfo TimeZoneInfo.Local . Viene generata un'eccezione anche se l'identificatore passato come parametro al metodo non è uguale a TimeZoneInfo.Local.Id .

Nell'esempio seguente viene utilizzato ConvertTime il metodo per eseguire la conversione dall'ora solare del Stati Uniti 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 non sono completamente in grado di riconoscere il fuso orario perché l'oggetto viene dissociato dal fuso orario al momento della creazione DateTimeOffset dell'istanza. In molti casi è tuttavia necessario convertire semplicemente una data e un'ora in base a due offset dall'ora UTC diversi anziché in base all'ora di determinati fusi orari. Per eseguire questa conversione, è possibile chiamare il metodo dell'istanza ToOffset corrente. Il singolo parametro del metodo è l'offset del nuovo valore di data e ora che deve essere restituito dal metodo.

Se, ad esempio, la data e l'ora della richiesta di una pagina Web da parte di un utente sono note e serializzate sotto forma di stringa nel formato MM/gg/aaaa hh:mm:ss zzzz, il metodo ReturnTimeOnServer seguente converte questo valore di data e ora nella data e nell'ora del 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 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 orario standard del Pacifico (Stati Uniti).

La TimeZoneInfo classe include anche un overload del metodo che esegue TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) conversioni del fuso orario con valori ToOffset(TimeSpan) . I parametri del metodo sono un valore e un riferimento al fuso orario in cui deve essere convertita DateTimeOffset l'ora. La chiamata al metodo restituisce un DateTimeOffset valore . Ad esempio, il ReturnTimeOnServer metodo nell'esempio precedente potrebbe essere riscritto come segue per chiamare il ConvertTime(DateTimeOffset, TimeZoneInfo) metodo .

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

Vedi anche