8

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?

Community
  • 1
  • 1
Dizzle
  • 1,026
  • 13
  • 26
  • Just a quick thought: you could check [IsDaylightSavingTime](https://msdn.microsoft.com/en-us/library/bb460642(v=vs.110).aspx) to detect a change between last run and current run. This means you'd need to track the result of the last run IsDaylightSavingTime and compare against the current run. – devlin carnate Nov 03 '15 at 15:32
  • you could save the date of the last "execution" of the event and prevent a second "execution" – Marco Forberg Nov 03 '15 at 15:39
  • i have updated my question with more information, and a sample of when the times conflict. – Dizzle Nov 03 '15 at 15:49
  • 1
    It's very unclear what you are asking for. The examples don't line up with your question, as Sweden's ambiguous time is between 2:00 and 3:00, and you said your repeated events were both before then. So those appointments are not ambiguous at all. Also, the first conflict time you showed is two hours long, which doesn't align with either of your 1 hour events. Additionally, please clarify what you mean by "how should I handle these". It's not clear what kind of answer you are looking for. Thanks. – Matt Johnson-Pint Nov 03 '15 at 17:22
  • 1
    One thing I can tell you right away, any time you leave Noda Time's API and go back to `DateTime`, you're probably introducing errors. (That should only be done when you need to interface to another API, such as reading and writing from a database.) – Matt Johnson-Pint Nov 03 '15 at 17:24
  • 1
    It's not clear what you mean by "conflicts" but fundamentally, you need to think about what you *want* to happen. I'd also suggest using `LocalDate` as the basis for your loop, rather than `ZonedDateTime`. That lets you loop by date - and then you can work out the times for each date in the specific zone. But we don't know what you want to happen, so we can't really provide any code... – Jon Skeet Nov 03 '15 at 18:05
  • @Jon Skeet, im trying to loop over the days within a range and create events which repeat in the future. The events can be created in different timezones and need to work in a specified "timeZone" due to the fact that a meeting at tuesday at 09:00 created in "Europe/Stockholm" needs to always be @ 09:00 for that timezone and thus approx 1 hour behind (08:00) depending on DST for people in "Europe/London". My current algorithm looked to be ok but on this date it seems to go wrong which is the first time it has incurred a negative time shift as the clocks change earlier in next year around march – Dizzle Nov 03 '15 at 18:17
  • Well yes, it will change UTC time, due to the DST changes. That's unsurprising. What's more potentially tricky is what happens if the local time is skipped or ambiguous. What do you *want* to happen for a meeting at 1.30am if the clock skips forward from 1am to 2am, meaning that 1.30am never happens? What do you *want* to happen for the same meeting when in the autumn the clock skips backward from 2am to 1am, so that 1.30am happens twice? Once you've answered those questions, Noda Time makes it easy to express those answers in code... but we can't answer the questions for you. – Jon Skeet Nov 03 '15 at 18:20
  • 1
    The bigger issue is that your code is incomplete above, and your examples don't line up with what you've described. I could attempt an answer if you can fix the question to align with the actual problem and show the full code that reproduces that problem. (see [MVCE](http://stackoverflow.com/help/mcve)) – Matt Johnson-Pint Nov 03 '15 at 18:22

1 Answers1

2

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.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575