Postupy: Použití časových pásem v aritmetických operacích s daty a časy
Obvykle když provádíte aritmetické operace s datem a časem pomocí hodnot DateTime nebo DateTimeOffset, výsledek nezohledňuje žádná pravidla úpravy časových pásem. To platí i v případě, že časové pásmo hodnoty data a času je jasně identifikovatelné (například když vlastnost Kind je nastavena na hodnotu 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 reflektovat pravidla pro úpravu časového pásma.
Chcete-li aplikovat pravidla úprav pro aritmetické operace s daty a časem
Implementujte některou metodu těsného spojení hodnoty data a času s příslušným časovým pásmem. Například deklarujte strukturu, která obsahuje hodnotu data a času a příslušnou hodnotu časového pásma. Následující příklad používá tento přístup k propojení hodnoty DateTime s příslušným časovým pásmem.
' 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; }
Převeďte čas na koordinovaný světový čas (standard UTC) voláním metody ConvertTimeToUtc nebo ConvertTime.
Provádění aritmetických operací na čase UTC.
Převeďte čas z času UTC na původní čas spojený s časovým pásmem voláním metody TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo).
Příklad
Následující příklad přidá dvě hodiny a 30 minut k hodnotě 9. března 2008 v 1:30 A.M. centrálního standardního času. K přechodu časového pásma na letní čas dojde o třicet minut později, ve 2:00 A.M. 9. března 2008. Protože příklad postupuje podle čtyř kroků uvedených v předchozím oddílu, správně hlásí výsledný čas jako 5:00 A.M. 9. března 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);
}
}
}
Obě hodnoty DateTime a DateTimeOffset nejsou přidružené k žádnému časovému pásmu, ke kterému by mohly patřit. K provádění aritmetických operací s datem a časem tak, aby se automaticky použila pravidla úprav časového pásma, časové pásmo, ke kterému hodnota data a času patří, musí být okamžitě identifikovatelné. To znamená, že datum a čas a jeho přidružené časové pásmo musí být pevně spojené. Existuje několik způsobů jak toto lze provést. Například následující:
Předpokládejme, že všechny časy použité v aplikaci vždy patří k určitému časovému pásmu. Ačkoli je toto v některých případech vhodné, tento přístup nabízí omezenou flexibilitu a případně i omezenou přenositelnost.
Definujte typ, který pevně spojuje datum a čas s jeho přidruženým časovým pásmem zahrnutím obojího jako pole typu. Tento přístup je použitý v příkladu kódu, který definuje strukturu pro uložení data a času a časového pásma ve dvou členských polích.
Příklad ukazuje, jak provádět aritmetické operace s hodnotami DateTime tak, aby byla na výsledek použita pravidla úpravy časového pásma. Avšak hodnoty DateTimeOffset lze použít stejně snadno. Následující příklad ukazuje, jak může být přizpůsoben kód v původním příkladu pro použití hodnoty DateTimeOffset místo hodnoty 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);
}
}
}
Všimněte si, pokud je toto přidání jednoduše provedeno pro hodnoty DateTimeOffset bez počátečního převodu na čas UTC, pak výsledek odráží konkrétní bod v čase, ale jeho posun toto nereflektuje od požadovaného časového pásma.
Probíhá kompilace kódu
Tento příklad vyžaduje:
Že bude do projektu přidán odkaz na System.Core.dll.
Že obor názvů System bude importován příkazem using (povinné v kódu jazyka C#).
Viz také
Koncepty
Provádění aritmetických operací s daty a časy