Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Chociaż zarówno struktury DateTime, jak i DateTimeOffset zapewniają elementy członkowskie, które wykonują operacje arytmetyczne na swoich wartościach, uzyskiwane wyniki tych operacji mogą się znacznie różnić. W tym artykule analizowane są te różnice, które odnoszą się do stopnia świadomości strefy czasowej w danych dotyczących daty i godziny, oraz omawia się, jak przeprowadzać operacje w pełni uwzględniające strefy czasowe z użyciem tych danych.
Porównania i operacje arytmetyczne z wartościami DateTime
Właściwość DateTime.Kind umożliwia przypisanie wartości DateTimeKind do daty i godziny, aby wskazać, czy reprezentuje czas lokalny, uniwersalny czas koordynowany (UTC) lub godzinę w nieokreślonej strefie czasowej. Jednak te ograniczone informacje o strefie czasowej są ignorowane podczas porównywania lub wykonywania arytmetyki daty i godziny dla wartości DateTimeKind. Poniższy przykład, który porównuje bieżącą godzinę lokalną z bieżącą godziną UTC, ilustruje sposób ignorowania informacji o strefie czasowej.
using System;
public enum TimeComparison2
{
EarlierThan = -1,
TheSameAs = 0,
LaterThan = 1
}
public class DateManipulation
{
public static void Main()
{
DateTime localTime = DateTime.Now;
DateTime utcTime = DateTime.UtcNow;
Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours",
localTime.Kind,
utcTime.Kind,
(localTime - utcTime).Hours,
(localTime - utcTime).Minutes);
Console.WriteLine("The {0} time is {1} the {2} time.",
localTime.Kind,
Enum.GetName(typeof(TimeComparison2), localTime.CompareTo(utcTime)),
utcTime.Kind);
}
}
// If run in the U.S. Pacific Standard Time zone, the example displays
// the following output to the console:
// Difference between Local and Utc time: -7:0 hours
// The Local time is EarlierThan the Utc time.
Public Enum TimeComparison As Integer
EarlierThan = -1
TheSameAs = 0
LaterThan = 1
End Enum
Module DateManipulation
Public Sub Main()
Dim localTime As Date = Date.Now
Dim utcTime As Date = Date.UtcNow
Console.WriteLine("Difference between {0} and {1} time: {2}:{3} hours", _
localTime.Kind.ToString(), _
utcTime.Kind.ToString(), _
(localTime - utcTime).Hours, _
(localTime - utcTime).Minutes)
Console.WriteLine("The {0} time is {1} the {2} time.", _
localTime.Kind.ToString(), _
[Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)), _
utcTime.Kind.ToString())
' If run in the U.S. Pacific Standard Time zone, the example displays
' the following output to the console:
' Difference between Local and Utc time: -7:0 hours
' The Local time is EarlierThan the Utc time.
End Sub
End Module
Metoda CompareTo(DateTime) zgłasza, że czas lokalny jest wcześniejszy niż czas UTC, a operacja odejmowania wskazuje, że różnica między czasem UTC a czasem lokalnym dla systemu w strefie czasowej standardowej czasu pacyficznego w Stanach Zjednoczonych wynosi siedem godzin. Jednak ponieważ te dwie wartości dostarczają różne reprezentacje jednego momentu w czasie, w tym przypadku jest jasne, że odstęp czasu jest całkowicie wynikiem przesunięcia lokalnej strefy czasowej względem UTC.
Ogólnie rzecz biorąc, właściwość DateTime.Kind nie ma wpływu na wyniki zwracane przez Kind metody porównania i arytmetyki (jak wskazuje porównanie dwóch identycznych punktów w czasie), chociaż może to mieć wpływ na interpretację tych wyników. Na przykład:
Wynik dowolnej operacji arytmetycznej wykonywanej na dwóch wartościach daty i godziny, których właściwości DateTime.Kind są równe DateTimeKind, odzwierciedla rzeczywisty przedział czasu między tymi dwiema wartościami. Podobnie porównanie dwóch takich wartości daty i godziny dokładnie odzwierciedla relację między godzinami.
Wynik dowolnej operacji arytmetycznej lub porównawczej wykonywanej na dwóch wartościach daty i godziny, które mają takie same wartości właściwości DateTime.Kind równe DateTimeKind, lub na dwóch wartościach daty i godziny z różnymi wartościami właściwości DateTime.Kind, odzwierciedla różnicę w czasie zegarowym między tymi dwiema wartościami.
Operacje arytmetyczne lub porównawcze w lokalnych wartościach daty i godziny nie uwzględniają, czy określona wartość jest niejednoznaczna, czy nieprawidłowa, ani nie uwzględniają wpływu żadnych reguł korekty, które wynikają z przejścia lokalnej strefy czasowej do lub z czasu letniego.
Każda operacja, która porównuje lub oblicza różnicę między czasem UTC a czasem lokalnym, w wyniku obejmuje interwał czasu równy przesunięciu lokalnej strefy czasowej względem UTC.
Każda operacja, która porównuje lub oblicza różnicę między nieokreślonym czasem a czasem UTC lub czasem lokalnym, odzwierciedla prosty czas zegara. Różnice strefy czasowej nie są brane pod uwagę, a wynik nie odzwierciedla zastosowania reguł korekty strefy czasowej.
Każda operacja, która porównuje lub oblicza różnicę między dwoma nieokreślonymi godzinami, może zawierać nieznany interwał, który odzwierciedla różnicę między czasem w dwóch różnych strefach czasowych.
Istnieje wiele scenariuszy, w których różnice strefy czasowej nie mają wpływu na obliczenia daty i godziny (w celu omówienia niektórych z tych scenariuszy zobacz Wybieranie między wartościami DateTime, DateTimeOffset, TimeSpan i TimeZoneInfo) lub w którym kontekst danych daty i godziny definiuje znaczenie operacji porównawczych lub arytmetycznych.
Porównania i operacje arytmetyczne z wartościami DateTimeOffset
Wartość DateTimeOffset zawiera nie tylko datę i godzinę, ale także przesunięcie, które jednoznacznie definiuje datę i godzinę względem czasu UTC. To przesunięcie umożliwia inny sposób definiowania równości niż w przypadku wartości DateTime. Natomiast DateTime wartości są równe, jeśli mają tę samą wartość daty i godziny, DateTimeOffset wartości są równe, jeśli oba odwołują się do tego samego punktu w czasie. W przypadku użycia w porównaniach i w większości operacji arytmetycznych, które określają interwał między dwiema datami i godzinami, wartość DateTimeOffset jest dokładniejsza i mniej potrzebna do interpretacji. Poniższy przykład, który jest DateTimeOffset odpowiednikiem poprzedniego przykładu porównującego wartości lokalne i UTC DateTimeOffset, ilustruje tę różnicę w działaniu.
using System;
public enum TimeComparison
{
EarlierThan = -1,
TheSameAs = 0,
LaterThan = 1
}
public class DateTimeOffsetManipulation
{
public static void Main()
{
DateTimeOffset localTime = DateTimeOffset.Now;
DateTimeOffset utcTime = DateTimeOffset.UtcNow;
Console.WriteLine($"Difference between local time and UTC: {(localTime - utcTime).Hours}:{(localTime - utcTime).Minutes:D2} hours");
Console.WriteLine($"The local time is {Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime))} UTC.");
}
}
// Regardless of the local time zone, the example displays
// the following output to the console:
// Difference between local time and UTC: 0:00 hours.
// The local time is TheSameAs UTC.
Public Enum TimeComparison As Integer
EarlierThan = -1
TheSameAs = 0
LaterThan = 1
End Enum
Module DateTimeOffsetManipulation
Public Sub Main()
Dim localTime As DateTimeOffset = DateTimeOffset.Now
Dim utcTime As DateTimeOffset = DateTimeOffset.UtcNow
Console.WriteLine("Difference between local time and UTC: {0}:{1:D2} hours.", _
(localTime - utcTime).Hours, _
(localTime - utcTime).Minutes)
Console.WriteLine("The local time is {0} UTC.", _
[Enum].GetName(GetType(TimeComparison), localTime.CompareTo(utcTime)))
End Sub
End Module
' Regardless of the local time zone, the example displays
' the following output to the console:
' Difference between local time and UTC: 0:00 hours.
' The local time is TheSameAs UTC.
' Console.WriteLine(e.GetType().Name)
W tym przykładzie metoda CompareTo wskazuje, że bieżąca godzina lokalna i bieżąca godzina UTC są równe, a odejmowanie wartości CompareTo(DateTimeOffset) wskazuje, że różnica między dwoma razy jest TimeSpan.Zero.
Głównym ograniczeniem używania wartości DateTimeOffset w arytmetyce daty i godziny jest to, że chociaż wartości DateTimeOffset uwzględniają częściowo strefy czasowe, nie są w pełni świadome stref czasowych. Mimo że przesunięcie wartości DateTimeOffset odzwierciedla przesunięcie strefy czasowej względem UTC w momencie pierwszego przypisania wartości zmiennej DateTimeOffset, później przestaje być związane ze strefą czasową. Ponieważ nie jest już bezpośrednio skojarzony z rozpoznawalnym czasem, dodawanie i odejmowanie interwałów daty i godziny nie uwzględnia reguł korekty strefy czasowej.
Aby zilustrować, przejście do czasu letniego w centralnej strefie czasowej w USA odbywa się o godzinie 2:00 w dniu 9 marca 2008 r. Mając to na uwadze, dodanie dwugodzinnego interwału do centralnego czasu standardowego 1:30 w dniu 9 marca 2008 r., powinno spowodować wygenerowanie daty i godziny 5:00 w dniu 9 marca 2008 r. Jednak, jak pokazano w poniższym przykładzie, wynik dodawania to 4:00 rano w dniu 9 marca 2008 r. Wynik tej operacji reprezentuje prawidłowy punkt w czasie, chociaż nie jest to czas w strefie czasowej, w której jesteśmy zainteresowani (czyli nie ma oczekiwanego przesunięcia strefy czasowej).
using System;
public class IntervalArithmetic
{
public static void Main()
{
DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
const string tzName = "Central Standard Time";
TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
// Instantiate DateTimeOffset value to have correct CST offset
try
{
DateTimeOffset centralTime1 = new DateTimeOffset(generalTime,
TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime));
// Add two and a half hours
DateTimeOffset centralTime2 = centralTime1.Add(twoAndAHalfHours);
// Display result
Console.WriteLine($"{centralTime1} + {twoAndAHalfHours.ToString()} hours = {centralTime2}");
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
}
}
}
// The example displays the following output to the console:
// 3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00
Module IntervalArithmetic
Public Sub Main()
Dim generalTime As Date = #03/09/2008 1:30AM#
Const tzName As String = "Central Standard Time"
Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
' Instantiate DateTimeOffset value to have correct CST offset
Try
Dim centralTime1 As New DateTimeOffset(generalTime, _
TimeZoneInfo.FindSystemTimeZoneById(tzName).GetUtcOffset(generalTime))
' Add two and a half hours
Dim centralTime2 As DateTimeOffset = centralTime1.Add(twoAndAHalfHours)
' Display result
Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
twoAndAHalfHours.ToString(), _
centralTime2)
Catch e As TimeZoneNotFoundException
Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
End Try
End Sub
End Module
' The example displays the following output to the console:
' 3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 4:00:00 AM -06:00
Operacje arytmetyczne z czasami stref czasowych
Klasa TimeZoneInfo zawiera metody konwersji, które automatycznie stosują korekty, gdy konwertują czasy z jednej strefy czasowej na inną. Te metody konwersji obejmują:
Metody ConvertTime i ConvertTimeBySystemTimeZoneId, które konwertują czasy między dwiema strefami czasowymi.
Metody ConvertTimeFromUtc i ConvertTimeToUtc, które konwertują czas w określonej strefie czasowej na UTC lub konwertują czas UTC na godzinę w określonej strefie czasowej.
Aby uzyskać szczegółowe informacje, zobacz Konwertowanie czasów między strefami czasowymi.
Klasa TimeZoneInfo nie udostępnia żadnych metod, które automatycznie stosują reguły korekty podczas wykonywania arytmetyki daty i godziny. Można jednak zastosować reguły korekty, konwertując czas w strefie czasowej na UTC, wykonując operację arytmetyczną, a następnie konwertując z czasu UTC z powrotem na czas w strefie czasowej. Aby uzyskać szczegółowe informacje, zobacz Jak: Używać stref czasowych w arytmetyce dat i czasu.
Na przykład poniższy kod jest podobny do poprzedniego kodu, który dodał dwie i pół godziny do 2:00 w dniu 9 marca 2008 r. Jednak ponieważ konwertuje środkowy czas standardowy na UTC przed wykonaniem arytmetyki daty i godziny, a następnie konwertuje wynik z czasu UTC z powrotem na środkowy czas standardowy, wynikowy czas odzwierciedla przejście centralnej standardowej strefy czasowej na czas letni.
using System;
public class TimeZoneAwareArithmetic
{
public static void Main()
{
const string tzName = "Central Standard Time";
DateTime generalTime = new DateTime(2008, 3, 9, 1, 30, 0);
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);
// Instantiate DateTimeOffset value to have correct CST offset
try
{
DateTimeOffset centralTime1 = new DateTimeOffset(generalTime,
cst.GetUtcOffset(generalTime));
// Add two and a half hours
DateTimeOffset utcTime = centralTime1.ToUniversalTime();
utcTime += twoAndAHalfHours;
DateTimeOffset centralTime2 = TimeZoneInfo.ConvertTime(utcTime, cst);
// Display result
Console.WriteLine($"{centralTime1} + {twoAndAHalfHours.ToString()} hours = {centralTime2}");
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to retrieve Central Standard Time zone information.");
}
}
}
// The example displays the following output to the console:
// 3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00
Module TimeZoneAwareArithmetic
Public Sub Main()
Const tzName As String = "Central Standard Time"
Dim generalTime As Date = #03/09/2008 1:30AM#
Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)
' Instantiate DateTimeOffset value to have correct CST offset
Try
Dim centralTime1 As New DateTimeOffset(generalTime, _
cst.GetUtcOffset(generalTime))
' Add two and a half hours
Dim utcTime As DateTimeOffset = centralTime1.ToUniversalTime()
utcTime += twoAndAHalfHours
Dim centralTime2 As DateTimeOffset = TimeZoneInfo.ConvertTime(utcTime, cst)
' Display result
Console.WriteLine("{0} + {1} hours = {2}", centralTime1, _
twoAndAHalfHours.ToString(), _
centralTime2)
Catch e As TimeZoneNotFoundException
Console.WriteLine("Unable to retrieve Central Standard Time zone information.")
End Try
End Sub
End Module
' The example displays the following output to the console:
' 3/9/2008 1:30:00 AM -06:00 + 02:30:00 hours = 3/9/2008 5:00:00 AM -05:00