3

I have an issue with the infamous daylight saving time.

I have a list of data points, one for each hour in a year. To check if all datapoints are present, I create a time iterator like this:

DateTime timeIterator = new DateTime(year, 1, 1, 0, 0, 0);

iterate it with

timeIterator = timeIterator.AddHours(1);

and check for each iteration if the point in time is present in the list.

The problem arises when it comes to daylight saving time. Im my example of year 2014, the clock is moved at the 30. of march from 0200 to 0300. So, after 0159 comes 0300. But DateTime.AddHours() completely ignores daylight saving. If timeIterator is at {30.03.2014 01:00:00} and I call AddHours(1) I get {30.03.2014 02:00:00} which obviously doesn't exist.

If I now test the list against this datapoint, it is (naturaly) not in the list and I throw a wrong "missing datapoint error".

How can I check, if my DateTime is a valid point in time?

Thanks in advance,
Frank

Aaginor
  • 4,516
  • 11
  • 51
  • 75

2 Answers2

2

How can I check, if my DateTime is a valid point in time?

Don't check, ensure it. You can count hours in UTC and translate each point to local time for example.

DateTimeOffset timeIterator = new DateTimeOffset(new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Local));
timeIterator = timeIterator.AddHours(1);
timeIterator.LocalDateTime;

// assuming you have a TimeZoneInfo object, you can also get different local times:
TimeZoneInfo tzi = /* the timezone */;
TimeZoneInfo.ConvertTimeFromUtc(timeIterator.UtcDateTime, tzi);

However, as Damien_The_Unbeliever commented, this only solves one part of the problem, the program will no longer check for the existance of an invalid date. A different problem arises when your data are stored with local times. This means that the transition from DST to normal time will have two successive hours with the same local DateTime representation. In order to avoid this situation, the data must be stored with complete information (UTC or explicit offset) so that later comparison is possible.

Edit:

If you have a valid TimeZoneInfo object for the timezone of your data and you don't want to switch over to DateTimeOffset for some reason, you can also use the following functions:

TimeZoneInfo tzi = /* the timezone */;
DateTime timeIterator = /* the time */;
if (tzi.IsAmbiguousTime(timeIterator))
{
    /* Expect multiple data entries */
}
if (tzi.IsInvalidTime(timeIterator))
{
    /* Expect no data entries */
}
grek40
  • 13,113
  • 1
  • 24
  • 50
  • The problem is, if they continue to store the dates as local times, they won't find if they have missing information at the other transition point in their year. E.g. if data was stored as 0100 UTC, 0200 UTC and 0400 UTC, but at 0300 UTC the clocks were set back, they'll have data at local times 0100, 0200 and 0300 but they were actually missing the data that should have been created at 0300 UTC which also maps to a local time of 0200, they still won't find it out here. – Damien_The_Unbeliever Dec 14 '16 at 15:35
  • @Damien_The_Unbeliever true story. If the question author is not checking external data (no influence) it's definitely time to improve the datetime storage. However, if the task is about inspecting existing historical data, then the damage is done and the double times can't be separated by value comparison anymore. Guess I gotta edit my question to clarify a few things. – grek40 Dec 14 '16 at 15:42
  • Hey guys, I check external data - and my problem is, that I eventually (daylight saving) check against a non valid date. The point is: I HAVE to know the timezone to avoid this, because otherwise I cannot know wheter this is a valid date or not. Guess I'll switch to NodaTime to handle it with more conscious ... – Aaginor Dec 15 '16 at 10:27
  • @Aaginor if you check data in the client timezone, my solution with `DateTimeOffset` and `LocalDateTime` should work for you (`DateTimeOffset.AddHours(1)` will increment local time by `0` or `2` hours on the DST transition point, which is different from `DateTime` behavior). Otherwise please be more precise in the question regarding your desired timezone, it should be easy to adopt the solution. – grek40 Dec 15 '16 at 10:41
  • Hey grek, your edit to your answer is pretty much what I do now. The client timezone is not "save" enough for me, because the data he loads might be from another timezone. So he need to tell me, from which timezone this data comes from. Switch to DataTimeOffset would be an option, but IF I switch (now I am just doing dirty quickhacks due to project time constraints) I'll switch to NodaTime. – Aaginor Dec 15 '16 at 15:36
0

I had also troubles with timezones. I advice you to save dates as UTC value

Then transform it: (maybe use an extention method)

private DateTime TransformToTimezone(DateTime datetime)
{
            TimeZoneInfo beZone = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");

            //Convert to timezone
            return TimeZoneInfo.ConvertTimeFromUtc(datetime, beZone);
}
Officer Jonez
  • 253
  • 2
  • 8
  • Yes, or store the timezone with my data (which I will probably do). ... and using NodaTime to get this more clear and transparent. – Aaginor Dec 15 '16 at 10:29