Instrukcje: Używanie stref czasowych w arytmetyce wartości daty i godziny
Zwykle podczas wykonywania arytmetyki daty i godziny przy użyciu DateTime wartości lub DateTimeOffset wynik nie odzwierciedla żadnych reguł korekty strefy czasowej. Jest to prawdą nawet wtedy, gdy strefa czasowa wartości daty i godziny jest wyraźnie rozpoznawalna (na przykład gdy Kind właściwość jest ustawiona na Localwartość ). W tym temacie pokazano, jak wykonywać operacje arytmetyczne w wartościach daty i godziny należących do określonej strefy czasowej. Wyniki operacji arytmetycznych będą odzwierciedlać reguły korekty strefy czasowej.
Aby zastosować reguły korekty do arytmetyki daty i godziny
Zaimplementuj metodę ścisłego sprzężenia wartości daty i godziny ze strefą czasową, do której należy. Na przykład zadeklaruj strukturę zawierającą zarówno wartość daty, jak i godziny oraz jej strefę czasową. W poniższym przykładzie użyto tej metody, aby połączyć wartość ze strefą DateTime czasową.
// 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
Przekonwertuj czas na uniwersalny czas koordynowany (UTC), wywołując metodę ConvertTimeToUtc lub metodę ConvertTime .
Wykonaj operację arytmetyczną w czasie UTC.
Przekonwertuj czas z UTC na powiązaną z oryginalną strefą czasową, wywołując metodę TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) .
Przykład
W poniższym przykładzie dodano dwie godziny i trzydzieści minut do 9 marca 2008 r., o godzinie 1:30 czasu centralnego (standardowego). Przejście strefy czasowej na czas letni przypada trzydzieści minut później o godzinie 2:00 w dniu 9 marca 2008 r. Ponieważ przykład jest zgodny z czterema krokami wymienionymi w poprzedniej sekcji, prawidłowo raportuje wynikowy czas 5:00 w dniu 9 marca 2008 r.
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
Obie DateTime wartości i DateTimeOffset nie są skojarzone z dowolną strefą czasową, do której mogą należeć. Aby wykonać arytmetyczną datę i godzinę w sposób, który automatycznie stosuje reguły korekty strefy czasowej, strefa czasowa, do której należy dowolna wartość daty i godziny, musi być natychmiast rozpoznawalna. Oznacza to, że data i godzina oraz skojarzona z nią strefa czasowa muszą być ściśle powiązane. Istnieje kilka sposobów, aby to zrobić, w tym następujące elementy:
Załóżmy, że wszystkie czasy używane w aplikacji należą do określonej strefy czasowej. Chociaż jest to odpowiednie w niektórych przypadkach, takie podejście zapewnia ograniczoną elastyczność i ewentualnie ograniczoną przenośność.
Zdefiniuj typ, który ściśle łączy datę i godzinę ze skojarzona strefą czasową, uwzględniając oba pola typu. To podejście jest używane w przykładzie kodu, który definiuje strukturę do przechowywania daty i godziny oraz strefy czasowej w dwóch polach składowych.
W przykładzie pokazano, jak wykonywać operacje arytmetyczne na DateTime wartościach, tak aby reguły korekty strefy czasowej były stosowane do wyniku. Jednak DateTimeOffset wartości mogą być używane tak samo łatwo. W poniższym przykładzie pokazano, jak kod w oryginalnym przykładzie może zostać dostosowany do użycia DateTimeOffset zamiast DateTime wartości.
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
Należy pamiętać, że jeśli ten dodatek jest po prostu wykonywany na DateTimeOffset wartości bez uprzedniej konwersji na UTC, wynik odzwierciedla prawidłowy punkt w czasie, ale jego przesunięcie nie odzwierciedla wartości wyznaczonej strefy czasowej dla tego czasu.