Rekenkundige bewerkingen uitvoeren met datums en tijden
Hoewel zowel de DateTime als de DateTimeOffset structuren leden bieden die rekenkundige bewerkingen uitvoeren op hun waarden, zijn de resultaten van rekenkundige bewerkingen heel anders. In dit artikel worden deze verschillen onderzocht, worden ze gerelateerd aan mate van tijdzonebewustzijn in datum- en tijdgegevens en wordt besproken hoe u volledig tijdzonebewuste bewerkingen uitvoert met datum- en tijdgegevens.
Vergelijkingen en rekenkundige bewerkingen met datum/tijd-waarden
Met DateTime.Kind de eigenschap kan een DateTimeKind waarde worden toegewezen aan de datum en tijd om aan te geven of deze lokale tijd, Coordinated Universal Time (UTC) of de tijd in een niet-opgegeven tijdzone vertegenwoordigt. Deze beperkte tijdzone-informatie wordt echter genegeerd bij het vergelijken of uitvoeren van datum- en tijdberekeningen op DateTimeKind waarden. In het volgende voorbeeld, waarin de huidige lokale tijd wordt vergeleken met de huidige UTC-tijd, ziet u hoe de tijdzone-informatie wordt genegeerd.
using System;
public enum TimeComparison
{
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(TimeComparison), 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
De CompareTo(DateTime) methode rapporteert dat de lokale tijd eerder is dan (of kleiner dan) de UTC-tijd en de aftrekkingsbewerking geeft aan dat het verschil tussen UTC en de lokale tijd voor een systeem in de Zone Us Pacific Standard Time zeven uur is. Maar omdat deze twee waarden verschillende weergaven van één bepaald tijdstip bieden, is het in dit geval duidelijk dat het tijdsinterval volledig is toe te schrijven aan de verschuiving van de lokale tijdzone van UTC.
Over het algemeen heeft de DateTime.Kind eigenschap geen invloed op de resultaten die worden geretourneerd door Kind vergelijkings- en rekenkundige methoden (zoals de vergelijking van twee identieke punten in de tijd aangeeft), hoewel dit van invloed kan zijn op de interpretatie van deze resultaten. Voorbeeld:
Het resultaat van een rekenkundige bewerking die wordt uitgevoerd op twee datum- en tijdwaarden waarvan DateTime.Kind beide overeenkomen DateTimeKind met het werkelijke tijdsinterval tussen de twee waarden. Op dezelfde manier weerspiegelt de vergelijking van twee dergelijke datum- en tijdwaarden de relatie tussen tijden nauwkeurig.
Het resultaat van een rekenkundige of vergelijkingsbewerking die wordt uitgevoerd op twee datum- en tijdwaarden waarvan DateTime.Kind de eigenschappen gelijk DateTimeKind zijn aan of op twee datum- en tijdwaarden met verschillende DateTime.Kind eigenschapswaarden, weerspiegelt het verschil in kloktijd tussen de twee waarden.
Rekenkundige of vergelijkingsbewerkingen op lokale datum- en tijdwaarden overwegen niet of een bepaalde waarde niet eenduidig of ongeldig is, noch houden ze rekening met het effect van eventuele aanpassingsregels die het gevolg zijn van de overgang van of naar de zomertijd van de lokale tijdzone.
Elke bewerking die het verschil tussen UTC en een lokale tijd vergelijkt of berekent, omvat een tijdsinterval dat gelijk is aan de offset van de lokale tijdzone van UTC in het resultaat.
Elke bewerking die het verschil vergelijkt of berekent tussen een niet-opgegeven tijd en UTC of de lokale tijd weerspiegelt een eenvoudige kloktijd. Verschillen in tijdzones worden niet meegenomen en het resultaat weerspiegelt niet de toepassing van regels voor het aanpassen van tijdzones.
Elke bewerking die het verschil tussen twee niet-opgegeven tijden vergelijkt of berekent, kan een onbekend interval bevatten dat het verschil tussen de tijd in twee verschillende tijdzones weergeeft.
Er zijn veel scenario's waarin verschillen in tijdzones geen invloed hebben op datum- en tijdberekeningen (zie Kiezen tussen Datum/tijd, DateTimeOffset, TimeSpan en TimeZoneInfo) of waarin de context van de datum- en tijdgegevens de betekenis van vergelijkings- of rekenkundige bewerkingen definieert.
Vergelijkingen en rekenkundige bewerkingen met DateTimeOffset-waarden
Een DateTimeOffset waarde bevat niet alleen een datum en tijd, maar ook een offset die die datum en tijd ondubbelzinnig definieert ten opzichte van UTC. Deze offset maakt het mogelijk om gelijkheid anders te definiëren dan voor DateTime waarden. Terwijl DateTime waarden gelijk zijn als ze dezelfde datum- en tijdwaarde hebben, DateTimeOffset zijn waarden gelijk als ze beide naar hetzelfde tijdstip verwijzen. Bij gebruik in vergelijkingen en in de meeste rekenkundige bewerkingen die het interval tussen twee datums en tijden bepalen, is een DateTimeOffset waarde nauwkeuriger en minder behoefte aan interpretatie. In het volgende voorbeeld, dat gelijk is aan het DateTimeOffset vorige voorbeeld waarin lokale en UTC-waarden DateTimeOffset zijn vergeleken, ziet u dit verschil in gedrag.
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: {0}:{1:D2} hours",
(localTime - utcTime).Hours,
(localTime - utcTime).Minutes);
Console.WriteLine("The local time is {0} UTC.",
Enum.GetName(typeof(TimeComparison), localTime.CompareTo(utcTime)));
}
}
// 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)
In dit voorbeeld geeft de CompareTo methode aan dat de huidige lokale tijd en de huidige UTC-tijd gelijk zijn en dat het aftrekken van CompareTo(DateTimeOffset) waarden aangeeft dat het verschil tussen de twee tijden is TimeSpan.Zero.
De belangrijkste beperking van het gebruik DateTimeOffset van waarden in datum- en tijdberekeningen is dat DateTimeOffset hoewel waarden enige tijdzonebewustzijn hebben, ze niet volledig op de hoogte zijn van de tijdzone. Hoewel de offset van de DateTimeOffset waarde overeenkomt met de offset van een tijdzone van UTC wanneer aan een variabele voor DateTimeOffset het eerst een waarde wordt toegewezen, wordt deze vervolgens losgekoppeld van de tijdzone. Omdat deze niet meer rechtstreeks aan een identificeerbare tijd is gekoppeld, worden de aanpassingsregels van een tijdzone niet overwogen door het optellen en aftrekken van datum- en tijdsintervallen.
Ter illustratie vindt de overgang naar zomertijd in de zone Amerikaanse centrale standaardtijd plaats om 2:00 uur op 9 maart 2008. Met dat in gedachten moet u op 9 maart 2008 op 9 maart 2008 een datum en tijd van 5:00 uur toevoegen aan een centrale standaardtijd van 1:30 uur. Zoals in het volgende voorbeeld wordt weergegeven, is het resultaat van de toevoeging echter 4:00 uur op 9 maart 2008. Het resultaat van deze bewerking vertegenwoordigt het juiste tijdstip, hoewel het niet de tijd is in de tijdzone waarin we geïnteresseerd zijn (dat wil gezegd, het heeft niet de verwachte tijdzone-offset).
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("{0} + {1} hours = {2}", centralTime1,
twoAndAHalfHours.ToString(),
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
Rekenkundige bewerkingen met tijden in tijdzones
De TimeZoneInfo klasse bevat conversiemethoden die automatisch aanpassingen toepassen wanneer ze tijden van de ene tijdzone naar de andere converteren. Deze conversiemethoden zijn onder andere:
De ConvertTime en ConvertTimeBySystemTimeZoneId methoden, waarmee tijden tussen twee tijdzones worden geconverteerd.
De ConvertTimeFromUtc en ConvertTimeToUtc methoden, waarmee de tijd in een bepaalde tijdzone wordt geconverteerd naar UTC of UTC worden geconverteerd naar de tijd in een bepaalde tijdzone.
Zie Tijd tussen tijdzones converteren voor meer informatie.
De TimeZoneInfo klasse biedt geen methoden die automatisch aanpassingsregels toepassen wanneer u rekenkundige datum- en tijdberekeningen uitvoert. U kunt echter aanpassingsregels toepassen door de tijd in een tijdzone te converteren naar UTC, de rekenkundige bewerking uit te voeren en vervolgens te converteren van UTC naar de tijd in de tijdzone. Zie Procedure: Tijdzones gebruiken in datum- en tijdberekeningen voor meer informatie.
De volgende code is bijvoorbeeld vergelijkbaar met de vorige code die twee en een half uur heeft toegevoegd aan 2:00 uur op 9 maart 2008. Omdat de functie echter een centrale standaardtijd converteert naar UTC voordat het rekenkundige datum- en tijdberekeningen uitvoert en vervolgens het resultaat van UTC weer converteert naar Central Standard-tijd, weerspiegelt de resulterende tijd de overgang van de Central Standard Time Zone naar zomertijd.
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("{0} + {1} hours = {2}", centralTime1,
twoAndAHalfHours.ToString(),
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