Procedura: utilizzare fusi orari nell'aritmetica di data e ora
Aggiornamento: novembre 2007
In genere, quando si esegue l'aritmetica di data e ora utilizzando i valori DateTime o DateTimeOffset, il risultato non riflette le regole di regolazione dei fusi orari. Questo vale anche quando il fuso orario del valore di data e ora è chiaramente identificabile, ad esempio quando la proprietà Kind è impostata su Local. In questo argomento viene illustrato come eseguire operazioni aritmetiche su valori di data e ora appartenenti a un determinato fuso orario. I risultati delle operazioni aritmetiche rifletteranno le regole di regolazione del fuso orario.
Per applicare le regole di regolazione all'aritmetica di data e ora
Implementare un metodo in base al quale un valore di data e ora è strettamente collegato al fuso orario al quale appartiene. Ad esempio, dichiarare una struttura che includa il valore di data e ora e il relativo fuso orario. Nell'esempio seguente viene utilizzato tale approccio per collegare un valore DateTime al relativo fuso orario.
' Define a structure for DateTime values for internal use only Friend Structure TimeWithTimeZone Dim TimeZone As TimeZoneInfo Dim Time As Date End Structure
// Define a structure for DateTime values for internal use only internal struct TimeWithTimeZone { TimeZoneInfo TimeZone; DateTime Time; }
Convert a time to Coordinated Universal Time (UTC) by calling either the ConvertTimeToUtc method or the ConvertTime method.
Eseguire l'operazione aritmetica sull'ora UTC.
Convert the time from UTC to the original time's associated time zone by calling the TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) method.
Esempio
Nell'esempio seguente vengono aggiunti due ore e trenta minuti al 9 marzo 2008, 1.30 Ora solare fuso centrale. La transizione del fuso orario a ora legale si verifica trenta minuti dopo, alle 2.00 del 9 marzo 2008. Poiché nell'esempio vengono seguiti i quattro passaggi riportati nella sezione precedente, l'orario corretto risultante sarà: 5.00 del 9 marzo 2008.
Public Structure TimeZoneTime
Public TimeZone As TimeZoneInfo
Public Time As Date
Public Sub New(tz As TimeZoneInfo, time As Date)
If tz Is Nothing Then _
Throw New ArgumentNullException("The time zone cannot be a null reference.")
Me.TimeZone = tz
Me.Time = time
End Sub
Public Function AddTime(interval As TimeSpan) As TimeZoneTime
' Convert time to UTC
Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
Me.TimeZone)
' Add time interval to time
utcTime = utcTime.Add(interval)
' Convert time back to time in time zone
Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
TimeZoneInfo.Utc, Me.TimeZone))
End Function
End Structure
Module TimeArithmetic
Public Const tzName As String = "Central Standard Time"
Public Sub Main()
Try
Dim cstTime1, cstTime2 As TimeZoneTime
Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
Dim time1 As Date = #03/09/2008 1:30AM#
Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
cstTime1 = New TimeZoneTime(cst, time1)
cstTime2 = cstTime1.AddTime(twoAndAHalfHours)
Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
twoAndAHalfHours.ToString(), _
cstTime2.Time)
Catch
Console.WriteLine("Unable to find {0}.", tzName)
End Try
End Sub
End Module
using System;
public struct TimeZoneTime
{
public TimeZoneInfo TimeZone;
public DateTime Time;
public TimeZoneTime(TimeZoneInfo tz, DateTime time)
{
if (tz == null)
throw new ArgumentNullException("The time zone cannot be a null reference.");
this.TimeZone = tz;
this.Time = time;
}
public TimeZoneTime AddTime(TimeSpan interval)
{
// Convert time to UTC
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
// Add time interval to time
utcTime = utcTime.Add(interval);
// Convert time back to time in time zone
return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime,
TimeZoneInfo.Utc, this.TimeZone));
}
}
public class TimeArithmetic
{
public const string tzName = "Central Standard Time";
public static void Main()
{
try
{
TimeZoneTime cstTime1, cstTime2;
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);
TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
cstTime1 = new TimeZoneTime(cst, time1);
cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
twoAndAHalfHours.ToString(),
cstTime2.Time);
}
catch
{
Console.WriteLine("Unable to find {0}.", tzName);
}
}
}
L'associazione di entrambi i valori DateTime e DateTimeOffset a un fuso orario al quale potrebbero appartenere viene annullata. Per eseguire l'aritmetica di data e ora in modo da applicare automaticamente le regole di regolazione di un fuso orario, è necessario che il fuso orario a cui appartiene il valore di data e ora sia immediatamente identificabile, ovvero che la data e ora e il relativo fuso orario associato siano strettamente collegati. Sono disponibili diversi modi per eseguire tale operazione, tra cui:
Presupporre che tutti gli orari utilizzati in un'applicazione appartengano a un determinato fuso orario. Sebbene adatto in alcuni casi, questo approccio ha una flessibilità limitata e talvolta anche una portabilità limitata.
Definire un tipo in base al quale una data e ora siano strettamente collegate al relativo fuso orario associato includendo entrambi i valori come campi del tipo. Questo approccio viene utilizzato nell'esempio di codice definendo una struttura per archiviare la data e ora e il fuso orario in due campi membro.
Nell'esempio viene illustrato come eseguire operazioni aritmetiche sui valori DateTime in modo da applicare le regole di regolazione del fuso orario al risultato. È possibile eventualmente utilizzare i valori DateTimeOffset altrettanto facilmente. Nell'esempio seguente viene illustrato come modificare il codice dell'esempio originale per l'utilizzo di DateTimeOffset anziché dei valori DateTime.
Public Structure TimeZoneTime
Public TimeZone As TimeZoneInfo
Public Time As DateTimeOffset
Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
If tz Is Nothing Then _
Throw New ArgumentNullException("The time zone cannot be a null reference.")
Me.TimeZone = tz
Me.Time = time
End Sub
Public Function AddTime(interval As TimeSpan) As TimeZoneTime
' Convert time to UTC
Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)
' Add time interval to time
utcTime = utcTime.Add(interval)
' Convert time back to time in time zone
Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
End Function
End Structure
Module TimeArithmetic
Public Const tzName As String = "Central Standard Time"
Public Sub Main()
Try
Dim cstTime1, cstTime2 As TimeZoneTime
Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
Dim time1 As Date = #03/09/2008 1:30AM#
Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
cstTime1 = New TimeZoneTime(cst, _
New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
cstTime2 = cstTime1.AddTime(twoAndAHalfHours)
Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
twoAndAHalfHours.ToString(), _
cstTime2.Time)
Catch
Console.WriteLine("Unable to find {0}.", tzName)
End Try
End Sub
End Module
using System;
public struct TimeZoneTime
{
public TimeZoneInfo TimeZone;
public DateTimeOffset Time;
public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
{
if (tz == null)
throw new ArgumentNullException("The time zone cannot be a null reference.");
this.TimeZone = tz;
this.Time = time;
}
public TimeZoneTime AddTime(TimeSpan interval)
{
// Convert time to UTC
DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);
// Add time interval to time
utcTime = utcTime.Add(interval);
// Convert time back to time in time zone
return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
}
}
public class TimeArithmetic
{
public const string tzName = "Central Standard Time";
public static void Main()
{
try
{
TimeZoneTime cstTime1, cstTime2;
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);
TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
cstTime1 = new TimeZoneTime(cst,
new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time,
twoAndAHalfHours.ToString(),
cstTime2.Time);
}
catch
{
Console.WriteLine("Unable to find {0}.", tzName);
}
}
}
Notare che se questa somma viene eseguita semplicemente sul valore DateTimeOffset senza prima convertirlo nell'ora UTC, il risultato rifletterà il momento esatto mentre l'offset relativo non rifletterà quello del fuso orario definito per tale orario.
Compilazione del codice
Per questo esempio è necessario:
Aggiungere un riferimento a System.Core.dll al progetto.
Importare lo spazio dei nomi System con l'istruzione using (richiesto nel codice C#).
Vedere anche
Concetti
Esecuzione di operazioni aritmetiche con date e ore