rossta / montrose

Recurring events library for Ruby. Enumerable recurrence objects and convenient chainable interface.

Home Page:https://rossta.net/montrose/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wrong event dates?

vitobotta opened this issue · comments

Hi! Many thanks for this gem, super useful.

I am having a problem with the recurrence persisted in the database returning event dates which differ from the event dates returned by the same recurrence before persisting, when using some time zone. Not sure if it makes sense but here's an example with Helsinki time zone (+2).

So if in a test I set the recurrence in a model like this:

    now = ActiveSupport::TimeZone["Helsinki"].parse("2016-09-10")
    Timecop.freeze now
    recurrence = Montrose.every(:week, on: %w(sunday tuesday), starts: now)
    @task.update_attributes recurrence: recurrence, ....

and I do

recurrence.events.take(5)

I get:

[Sun, 11 Sep 2016 00:00:00 EEST +03:00, Tue, 13 Sep 2016 00:00:00 EEST +03:00, Sun, 18 Sep 2016 00:00:00 EEST +03:00, Tue, 20 Sep 2016 00:00:00 EEST +03:00, Sun, 25 Sep 2016 00:00:00 EEST +03:00]

But if I do the same after saving the model, loading the recurrence through the model:

@task.recurrence.events.take(5)

I get:

[Sun, 11 Sep 2016 21:00:00 UTC +00:00, Tue, 13 Sep 2016 21:00:00 UTC +00:00, Sun, 18 Sep 2016 21:00:00 UTC +00:00, Tue, 20 Sep 2016 21:00:00 UTC +00:00, Sun, 25 Sep 2016 21:00:00 UTC +00:00]

It converts the date to UTC but for example the first date should be Sep 10 with the same time in UTC, not Sep 11.

Am I missing something?

Thanks in advance!

Uhm not sure if I am understanding correctly the way the dates are calculated. E.g.

=> #<Montrose::Recurrence:2ac54cba6d78 {:every=>:week, :starts=>Sat, 10 Sep 2016 21:00:00 UTC +00:00, :day=>[1, 4], :interval=>3, :total=>10, :on=>["monday", "thursday"]}>
>> t.reload.recurrence.events.to_a
=> [2016-09-26 21:00:00 +0000, 2016-09-29 21:00:00 +0000, 2016-10-17 21:00:00 +0000, 2016-10-20 21:00:00 +0000, 2016-11-07 21:00:00 +0000, 2016-11-10 21:00:00 +0000, 2016-11-28 21:00:00 +0000, 2016-12-01 21:00:00 +0000, 2016-12-19 21:00:00 +0000, 2016-12-22 21:00:00 +0000]

The first occurrence is 26/9 (UTC) - why does it jump to that date for the first occurrence? Shouldn't it be 11/9 (UTC), starting from the first possible occurrence according to the schedule (monday and thursday in the example, so the first monday starting from Sep 10 is Sep 11, in UTC) and then skip two weeks after that?

Thanks.

I think I understood the problem.... the beginning of the week is assumed to be Monday, not Sunday, can you confirm? Thanks

Hi @vitobotta - you're asking two separate questions which I'll address:

  1. There may be a bug with serializing/deserializing times with respect to time zone. Assuming you're using Rails and the app configuration for time zone is set to UTC, i.e. config.time_zone = 'UTC', I would expect the deserialized dates to be in the UTC time zone as appears to be the case, but to reflect at the same time as originally set when you originally created the object. So the behavior you're seeing warrants some investigation.
  2. For your other question about recurrence every 3 weeks, the behavior you're seeing is what I would expect. For the intervals by week, the first week of the interval is set to the week of the start date, regardless of whether or not the days you're asking for will occur later in the week with respect to that start date. If you want to ensure that the upcoming Monday is the first date in the enumeration, you could use something like starts: Date.today.next_week.

@vitobotta So, the time zone recurrence question is not straightforward. You're seeing this behavior because you're serializing a recurrence start time in one time zone and deserializing it in another, and that recurrence is supposed to occur on a given day(s).

For the example you've given, the start time is a different day in the two time zones. So when you ask for the deserialized recurrence in UTC, the first event when using Helsinki time zone, Sun, 11 Sep 2016 00:00:00 EEST +03:00, would no longer fall on Sunday in UTC, so it's not a valid event for that time zone.

One way to ensure you deserialize the recurrence correctly is to wrap it in Time.use_zone block:

Time.use_zone("Helsinki") do
  @task = Task.find(task_id)
  @task.recurrence.events.take(5)
end

We could entertain an option for "locking" the recurrence time zone so that's done automatically, but I'm not sure what that would look like.

Hi @rossta

Thanks a lot for getting back to me and sorry for the delay (been sick). Working fine now, thank you for your help!

@rossta does this still work? #62 (comment)

Just testing it and seems like it's still returning local timezone, not the timezone specified