Conversione degli orari tra fusi orari

È sempre più importante per qualsiasi applicazione che funziona con date e orari per gestire le differenze tra i fusi orari. Un'applicazione non può più presumere che tutti i tempi possano essere espressi nell'ora locale, ovvero il tempo disponibile dalla DateTime struttura. Ad esempio, una pagina Web che visualizza l'ora corrente nella parte orientale della Stati Uniti non avrà credibilità per un cliente nell'Asia orientale. Questo articolo illustra come convertire i tempi da un fuso orario a un altro e convertire DateTimeOffset i valori con consapevolezza limitata del fuso orario.

Conversione nel formato UTC

UTC (Coordinated Universal Time) è uno standard di alta precisione basato sul tempo atomico. I fusi orari del mondo vengono espressi come offset positivi o negativi da UTC. In questo modo, UTC fornisce un fuso orario libero o un fuso orario neutrale. L'uso dell'ora UTC è consigliato quando la portabilità di una data e dell'ora tra i computer è importante. Per informazioni dettagliate e altre procedure consigliate che usano date e ore, vedere Procedure consigliate per la codifica con DateTime in .NET Framework. La conversione di singoli fusi orari in ore UTC semplifica i confronti tra gli orari.

Nota

È anche possibile serializzare una struttura per rappresentare un DateTimeOffset singolo punto nel tempo senza ambiguità. Poiché DateTimeOffset gli oggetti archiviano un valore di data e ora insieme al relativo offset da UTC, rappresentano sempre un determinato punto di tempo rispetto all'ora UTC.

Il modo più semplice per convertire un'ora utc consiste nel chiamare il static metodo (Shared in Visual Basic). TimeZoneInfo.ConvertTimeToUtc(DateTime) La conversione esatta eseguita dal metodo dipende dal valore della proprietà del dateTimeKind 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 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 ToUniversalTime metodo restituirà probabilmente un risultato errato. È tuttavia possibile usare il metodo per convertire la data e l'ora TimeZoneInfo.ConvertTimeToUtc da un fuso orario specificato. Per informazioni dettagliate sul recupero di un TimeZoneInfo oggetto che rappresenta il fuso orario di destinazione, vedere Ricerca dei fusi orari definiti in un sistema locale. Il codice seguente usa il metodo per convertire l'ora TimeZoneInfo.ConvertTimeToUtc standard 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 {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

Il TimeZoneInfo.ConvertTimeToUtc metodo genera un valore ArgumentException se la DateTime proprietà dell'oggetto Kind e il fuso orario non corrispondono. Una mancata corrispondenza si verifica se la Kind proprietà è ma l'oggetto non rappresenta il TimeZoneInfo fuso orario locale o se la proprietà è DateTimeKind.Local ma l'oggetto KindTimeZoneInfo non è DateTimeKind.Utc uguale TimeZoneInfo.Utca .

Tutti questi metodi accettano DateTime valori come parametri e restituiscono un DateTime valore. Per DateTimeOffset i valori, la DateTimeOffset struttura ha un ToUniversalTime metodo di istanza che converte la data e l'ora dell'istanza corrente in UTC. Nell'esempio seguente viene chiamato il ToUniversalTime metodo per convertire un'ora locale e diverse 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: {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 nell'ora locale, vedere la sezione seguente Conversione dell'ora UTC nell'ora locale. Per convertire UTC nell'ora in qualsiasi fuso orario designato, chiamare il ConvertTimeFromUtc metodo . Il metodo accetta due parametri:

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

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

Il codice seguente converte UTC in Ora standard 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 utc in ora locale, chiamare il ToLocalTime metodo dell'oggetto DateTime il cui tempo si vuole convertire. 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 Si presuppone che il DateTime valore sia UTC e converte l'ora UTC in ora locale.
DateTimeKind.Utc Converte il DateTime valore in ora locale.

Nota

Il TimeZone.ToLocalTime metodo si comporta in modo identico al DateTime.ToLocalTime metodo. Accetta un singolo parametro, ovvero il valore data e ora, per la conversione.

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

Conversione tra due fusi orari

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

  • ConvertTime

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

  • ConvertTimeBySystemTimeZoneId

    I parametri di questo metodo sono il valore di data e ora da convertire, l'identificatore del fuso orario della data e dell'ora e l'identificatore del fuso orario in cui convertire il valore di data e ora.

Entrambi i metodi richiedono che la Kind proprietà del valore di data e ora per convertire e l'identificatore del fuso orario o dell'oggetto che rappresenta il fuso orario corrispondano l'uno all'altro TimeZoneInfo . In caso contrario, verrà generata un'eccezione ArgumentException. Ad esempio, se la Kind proprietà 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.

Nell'esempio seguente viene usato il metodo per convertire dall'ora standard hawaiiana all'ora ConvertTime 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 DateTimeOffset oggetti non sono completamente consapevoli del fuso orario perché l'oggetto viene disassociato dal relativo fuso orario alla volta in cui viene creata un'istanza. Tuttavia, in molti casi, un'applicazione deve semplicemente convertire una data e un'ora in base a due offset diversi da UTC anziché in orario in determinati fusi orari. Per eseguire questa conversione, è possibile chiamare il metodo dell'istanza ToOffset corrente. Il parametro singolo del metodo è l'offset del nuovo valore di data e ora restituito dal metodo.

Ad esempio, se la data e l'ora di una richiesta utente per una pagina Web è nota e viene serializzata come stringa nel formato MM/dd/a hh:mm:ss zzzz, il metodo seguente ReturnTimeOnServer converte questo valore di 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 di 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 TimeZoneInfo classe include anche un overload del metodo che esegue conversioni del TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) fuso orario con ToOffset(TimeSpan) valori. I parametri del metodo sono un valore e un DateTimeOffset riferimento al fuso orario in cui deve essere convertito l'ora. La chiamata al metodo restituisce un DateTimeOffset valore. Ad esempio, il ReturnTimeOnServer metodo nell'esempio precedente può 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