How to Store Repeating Dates Keeping in Mind Daylight Savings Time

How to store repeating dates keeping in mind Daylight Savings Time

First, please recognize that in modern terminology you should say UTC instead of GMT. They are mostly equivalent, except that UTC is more precisely defined. Reserve the term GMT to refer to the portion of the time zone in the United Kingdom that is in effect during the winter months having the offset UTC+0.

Now to your question. UTC is not necessarily the best way to store all date and time values. It works particularly well for past events, or for future absolute events, but it doesn't work so great for future local events - especially future recurring events.

I wrote about this on another answer recently, and is one of the few exception cases where local time makes more sense than UTC. The main argument is the "alarm clock problem". If you set your alarm clock by UTC, you'll be waking up an hour early or late on the day of the DST transitions. This is why most folks set their alarm clocks by local time.

Of course, you can't just store a local time if you are working with data from all over the world. You should store a few different things:

  • The local time of the recurring event, such as "08:00"
  • The time zone that the local time is expressed in, such as "America/New_York"
  • The recurrence pattern, in whatever format makes sense for your application, such as daily, bi-weekly, or the third Thursday of the month, etc.
  • The next immediate UTC date and time equivalent, to the best that you can project it.
  • Perhaps, but not always, a list of future event UTC date and times, projected out some predefined period into the future (perhaps a week, perhaps 6 months, perhaps a year or two, depending on your needs).

For the last two, understand that the UTC equivalent of any local date/time can change if the government responsible for that time zone decides to change anything. Since there are multiple time zone database updates every year, you will want to have a plan to subscribe to announcements of updates and update your timezone database regularly. Whenever you update your timezone data, you'll need to recalculate the UTC equivalent times of all future events.

Having the UTC equivalents is important if you plan to show any kind of list of events spanning more than one time zone. Those are the values you'll query to build that list.

Another point to consider is that if an event is scheduled for a local time that occurs during a DST fall-back transition, you will have to decide whether the event occurs on the first instance (usually), or the second instance (sometimes), or both (rarely), and build into your application a mechanism to ensure the event doesn't fire twice unless you want it to.

If you were looking for a simple answer - sorry, but there isn't one. Scheduling future events across time zones is a complicated task.

Alternative Approach

I've had a few people show me a technique where they do use UTC time for scheduling, which is that they pick a starting date in local time, convert that to UTC to be stored, and store the time zone ID as well. Then at runtime, they apply the time zone to convert the original UTC time back to local time, then use that local time to compute the other recurrences, as if it were the one originally stored as above.

While this technique will work, the drawbacks are:

  • If there's a time zone update that changes the local time before the first instance is run, it will throw the whole schedule off. This can be mitigated by choosing a time in the past for the "first" instance, such that the second instance is really the first one.

  • If the time is really a "floating time" that should follow the user around (such as in an alarm clock on a cell phone), you'd still have to store time zone information for the zone it was originally created in - even if that's not the zone you want to run in.

  • It adds additional complexity without any benefit. I'd reserve this technique for situations where you may have had a UTC-only scheduler that you're trying to retrofit time zone support into.

How to store daylight savings time adjusted utc time

Figured it out. Special thanks to @MarkLakata for pointing out the differences between PDT and PST. Turns out we can't rely on these to play with dates. In my app, I do know the geographic location of my Property though. For now, it's "Pacific Time (US & Canada)", but later I may have properties from many other locations. I want to schedule cleanings in the future. In the real world, people don't usually reschedule around DST. So if I say I'm doing something at 4:15pm, I mean it whether it's DST or not, and I need my app to behave the same way.

property.timezone
=> "Pacific Time (US & Canada)"

Time.zone = property.timezone
=> "Pacific Time (US & Canada)"

time = Time.zone.parse("2013-12-08 04:15pm").utc
=> 2013-12-09 00:15:00 UTC

time = Time.zone.parse("2013-10-08 04:15pm").utc #DST
=> 2013-10-08 23:15:00 UTC

I store my cleaning_date attribute in a PostgreSQL DateTime field on Heroku. I know the timezone from the property, so I can save it after I parse it from the front end.

property.update(:cleaning_time => time)

To get it back from the database, I just do this:

def cleaning_date_string
self.cleaning_time.in_time_zone("Pacific Time (US & Canada)").strftime("%m/%d/%Y")
end

def cleaning_time_string
self.cleaning_time.in_time_zone("Pacific Time (US & Canada)").strftime("%l:%M%P")
end

Unfortunately, this is the only way I found to save a precise time in the database and retrieve it the exact same way. This seems to work locally and on Heroku.

addition:

This seems to be thread safe according to:
Setting Time.zone during a request: Thread Safe?

Bug creating recurring events in daylight savings time with Google Calendar API?

Can it be that you have a timezone defined in the start.dateTime and end.dateTime as well? I looks like the timeZone field is not fully recognized if this is done. Try changing your dates from "2012-09-26T10:00:00.000-00:00" to just "2012-09-26T10:00:00.000" [API->start.dateTime]

As GMT is without DST, if you put a calendar event as the one you specified, starting at 10:00 GMT, when looking at the calendar view with your local time set to "Europe/Dublin" these events will start at 11:00 as summer time is +1.

I'm not sure what you mean with "independent" of timezone, but:

1) If you want a recurring event that start at 10:00 Irish time weekly until december (as shown on your wall clock), try this:

{
"start": {
"dateTime": "2012-09-26T10:00:00.000",
"timeZone": "Europe/Dublin"
},
"end": {
"dateTime": "2012-09-26T11:00:00.000",
"timeZone": "Europe/Dublin"
},
"summary": "CS101 Dublin",
"description": "Intro to Comp Sci",
"location": "Bla bla bla",
"recurrence": [
"RRULE:FREQ=WEEKLY;UNTIL=20121131"
]
}

2) If you in fact want the event to start at 10:00 GMT weekly until december (as shown on a clock that is always set to winter time in Ireland), try this:

{
"start": {
"dateTime": "2012-09-26T10:00:00.000",
"timeZone": "GMT"
},
"end": {
"dateTime": "2012-09-26T11:00:00.000",
"timeZone": "GMT"
},
"summary": "CS101 GMT",
"description": "Intro to Comp Sci",
"location": "Bla bla bla",
"recurrence": [
"RRULE:FREQ=WEEKLY;UNTIL=20121131"
]
}

This will create an event that, when shown in a calendar UI with a timezone set to "Europe/Dublin" is at 11:00 until 2012-10-31, when it will start at 10:00. You can try to switch between different time zone displays in the Calendar UI on flower button->settings->your timezone.

But my guess would be that you want (1) here, as it sounds like a CS course that would start with a time specified in local time.

Btw, when trying things out if find the API explorer pretty handy: https://developers.google.com/apis-explorer/#s/calendar/v3/



Related Topics



Leave a reply



Submit