Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle when timezone goes backwards in the future

I am generating two sets of repeating events in seperate loop iterations but am having a conflict when comparing the generated results for conflicts. This seems to be when the times go backwards and I am unsure how to solve this?

The first repeat event will:

  • repeat everyday at 00:00 to 01:00 in "Europe/Stockholm" time
  • from 03/11/2015
  • looping until forever.

The second repeat event will:

  • repeat everyday at 01:00 to 02:00 in "Europe/Stockholm" time
  • from 03/11/2015
  • again looping forever.

To generate the events I am looping through everyday in the local time zone "Europe/Stockholm" using Nodatime like this:

String timeZone = "Europe/Stockholm";
for (ZonedDateTime date_Local = repeatSeriesStartDate_Local; date_Local <= LoopEndDate_Local; date_Local = new ZonedDateTime(Instant.FromDateTimeUtc(date_Local.ToDateTimeUtc().AddDays(1).ToUniversalTime()),timeZone))

My issue arises on October 29/30th 2016 When the clocks go backwards and the 2nd rule conflicts with the first. http://www.timeanddate.com/time/change/sweden/stockholm?year=2016

The conflict times are as follows:

  • "2016-10-29T23:00:00Z" to "2016-10-30T01:00:00Z"
  • "2016-10-30T00:00:00Z" to "2016-10-30T01:00:00Z"

I am using an algorithm like this one to test for conflicts https://stackoverflow.com/a/325964/884132

How should I handle these time shifting conflicts?

like image 390
Dizzle Avatar asked Nov 03 '15 15:11

Dizzle


1 Answers

Though it would really help if you'll clarify the question, I'll make a few assumptions for now. I can edit the question later if necessary.

What you probably want to do is something like this:

for (LocalDate date = startDate; date <= endDate; date = date.PlusDays(1))
{
    ZonedDateTime zdt = date.At(eventTime).InZone(tz, SchedulingResolver);
    Console.WriteLine(zdt); // or whatever you want to do from here
}

The SchedulingResolver implementation is here, and is only necessary if you are using the 1.x version of Noda Time. If you are using 2.x, then you can just use InZoneLeniently(tz) instead, as the behavior of the lenient resolver in 2.x has changed to match (see "lenient resolver changes" in the 2.x migration guide).

The key points are:

  • ZonedDateTime is often best used as an intermediary type.

    • You have daily events that are based on the local day, so LocalDate is more appropriate.

    • If you had events based on a fixed 24-hour rotation (aka, the UTC day), then Instant would be more appropriate.

  • Resolvers are used to map ambiguous or invalid LocalDateTime values back to specific moments in time. The resolver I recommend for scheduling purposes is the one that:

    • Advances by the DST bias (usually 1 hour) when the clocks go forward (spring)
    • Picks the first instance when the clocks go back (fall)

Though as Jon mentioned - your needs may vary, and really we can't answer what you should do. There are indeed business that need different resolver rules than the ones I am recommending.

like image 120
Matt Johnson-Pint Avatar answered Sep 18 '22 07:09

Matt Johnson-Pint