Postupy: Používání časových pásem v aritmetice kalendářních a časových údajů
Obvykle platí, že pokud provádíte aritmetické aritmetické DateTime DateTimeOffset hodnoty kalendářního data a času, výsledek neodráží žádná pravidla pro úpravy časového pásma. To platí i v případě, že časové pásmo hodnoty data a času je jasně identifikovatelné (například když Kind je vlastnost nastavena na Local). Toto téma ukazuje, jak provádět aritmetické operace s hodnotami data a času, které patří do určitého časového pásma. Výsledky aritmetických operací budou odrážet pravidla úprav časového pásma.
Použití pravidel úpravy na aritmetické aritmetické datum a čas
Implementujte určitou metodu úzce spárované hodnoty data a času s časovým pásmem, ke kterému patří. Deklarujte například strukturu, která zahrnuje hodnotu data a času i její časové pásmo. Následující příklad používá tento přístup k propojení hodnoty s časovým DateTime pásmem.
// Define a structure for DateTime values for internal use only internal struct TimeWithTimeZone { TimeZoneInfo TimeZone; DateTime Time; }
' Define a structure for DateTime values for internal use only Friend Structure TimeWithTimeZone Dim TimeZone As TimeZoneInfo Dim Time As Date End Structure
Převeďte čas na koordinovaný univerzální čas (UTC) voláním ConvertTimeToUtc metody nebo ConvertTime metody.
Proveďte aritmetickou operaci v čase UTC.
Převeďte čas z UTC na časové pásmo přidružené k původnímu času voláním TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) metody.
Příklad
Následující příklad přidá dvě hodiny a třicet minut do 9. března 2008 v 1:30 střední standardní čas. Přechod časového pásma na letní čas nastane o třicet minut později v 9. březnu 2008 v 2:00. Vzhledem k tomu, že příklad se řídí čtyřmi kroky uvedenými v předchozí části, správně hlásí výsledný čas 9. března 2008 jako 5:00.
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);
}
}
}
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
Obě DateTime hodnoty DateTimeOffset se oddělují od jakéhokoli časového pásma, do kterého můžou patřit. Aby bylo možné provádět aritmetické aritmetické hodnoty data a času způsobem, který automaticky použije pravidla úpravy časového pásma, musí být časové pásmo, do kterého patří jakákoli hodnota data a času, okamžitě identifikovatelná. To znamená, že datum a čas a jeho přidružené časové pásmo musí být úzce svázané. Existuje několik způsobů, jak to udělat, mezi které patří:
Předpokládejme, že všechny časy používané v aplikaci patří do určitého časového pásma. I když je tento přístup v některých případech vhodný, nabízí omezenou flexibilitu a možná omezenou přenositelnost.
Definujte typ, který úzce páruje datum a čas s přidruženým časovým pásmem, a to tak, že zahrne obě pole typu. Tento přístup se používá v příkladu kódu, který definuje strukturu pro uložení data a času a časového pásma ve dvou polích členů.
Tento příklad ukazuje, jak provádět aritmetické operace s DateTime hodnotami, aby se na výsledek použila pravidla úpravy časového pásma. DateTimeOffset Hodnoty se ale dají použít stejně snadno. Následující příklad ukazuje, jak může být kód v původním příkladu upraven tak, aby používal DateTimeOffset místo DateTime hodnot.
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);
}
}
}
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
Všimněte si, že pokud je toto sčítání jednoduše provedeno s DateTimeOffset hodnotou bez prvního převodu na UTC, výsledek odráží správný bod v čase, ale jeho posun neodráží hodnotu určeného časového pásma pro daný čas.