Accounting for daylight savings in rails webapp and iCal - ruby-on-rails

Right, this is a bit confusing for me, so I'm going to try and explain from the top!
I have a rails web app. It's an internal company app and will only be used in the UK.
One of the things the app does is manage meetings.
Meetings have a date & time when they start. There's a date/time picker on the form which allows the user to pick the date & time the meeting is for. I save this date AS IS into the database. All meetings last 2 hours, so the end time is simply start + 2 hours.
Example:
2013-06-23 6:45PM in the form is stored in the db as 2013-06-23 18:45:00
2013-12-23 6.45pm in the form is stored in the db as 2013-12-23 18:45:00
Note that the first date is during Daylight Savings (BST) and the second is during GMT. I don't actually care whether it is GMT or BST: the meeting happens at that time, absolutely.
Inside the rails webapp, I simply print out the exact date & time from the DB - formatted nicely, of course!
Now, at some point I send an email to the organiser of the meeting, and the person they're meeting with. This email tells them the the date & time of the meeting etc, and also includes an iCal (.ics) file for them to put into their (Outlook usually, but also Apple or gmail) calendar.
The issue I am having is that (using the above examples) Outlook shows the meetings like this:
Meeting #1: Start: 23/06/2013 7:45pm, End: 23/06/2013 9:45pm
Meeting #2: Start: 23/12/2013 6:45pm, End: 23/12/2013 8:45pm
Note that it has adjusted the first one because of the BST/GMT thing.
The text of the .ics file contains this code:
Meeting #1:
BEGIN:VCALENDAR
...
DTEND:20130623T204500Z
DTSTART:20130623T184500Z
...
END:VCALENDAR
Meeting #2:
BEGIN:VCALENDAR
...
DTEND:20131223T204500Z
DTSTART:20131223T184500Z
...
END:VCALENDAR
So I am encoding the dates/times using the Z timezone (UTC). I understand this is why Outlook mis converting the UTC time into the BST time for #1 and leaving #2 alone (because GMT == UTC)
My question is: how do I stop this happening? I want the time the meeting is scheduled for to be the absolute, actual time, regardless of GMT/BST: 6:45pm
Should I be storing the date-times as UTC in the DB? How would this be done (I assume it would apply to all dates, not just meeting start dates). And how to re-convert them back into the actual datetime when I display them in the webapp?
Extra:
I have an entry in my initializers/time_formats.rb like this:
:ical => "%Y%m%dT%H%M00Z"
So dates come out like "20130623T184500Z". I use this when building the ics. And this I think is the issue - if the date/time is during BST I don't want to be using Z, but something else?

Your problem is your date/time format. You have:
DTSTART:20130623T184500Z
in your .ics file and this corresponds to 19:45 BST (as British summer time is UTC+1).
There are a few things you should do. First, you can simply remove the 'Z' from the end of your dates. This means that the times inherit the timezone of the calendar, or the underlying application.
This will work assuming that the machines which are running Outlook are all in the Europe/London timezone. If not, or if you want to be a bit safer, you should also specify the following after your BEGIN: VCALENDAR line:
X-WR-TIMEZONE:Europe/London
This specifies the default timezone for all dates which are not specified explicitly.
Finally, if this does not work for any reason then you need to define your datetimes explicitly. First you need to add a timezone definition for Europe/London to the calendar. The info you need is available at http://www.tzurl.org/zoneinfo-outlook/Europe/London.ics. Then you need to ensure that all datetimes are of the format:
DTSTART;TZID=Europe/London:20130623T184500
This last approach is the best, as it means that if your requirements expand to other timezones you will be able to handle them relatively easily.

Sorry to answer this myself, but in case anyone else runs into this here's what I found was the cause of my particular issue. Note that the answer above re timezones also makes sense!
My rails app is storing UTC datetimes in the DB (as is default)
But, it also thought it's own timezone was UTC, which also seems to be the default.
The upshot of that is essentially it was storing local dates, local to UTC anyway. Changing the app to know it was sitting in Europe/London made it so the dates in the DB are all now accurately UTC (meaning, they're an hour off if I'm currently in BST)
I can now use the Z datetime format in iCals, and outlook and the rails app both convert the UTC date back into the actual datetime for the viewing-user's locale (Europe/London for everyone at the moment). This is what I wanted.

Related

What is the opposite of an AoE expiry?

I'm speccing an application that displays time periods to the user. The goal is to present periods in a simple view (no time, no timezones) and detailed view (date and time, with timezone data). The simple view should be unambiguous, in other words the user can glance at it and their assumptions about what they see are correct (they are valid in the local timezone).
For the end of the global period, displaying the date in the AoE timezone [1] will solve this problem. For example, a submission deadline might display as 2018-04-03 (actually 2018-04-03 23:59:59 AoE). This means submissions are accepted as long as it is April 3 somewhere on the planet.
But I also want to indicate that start of a global period. For example, if submissions open on April 2 2018 00:01, they are accepted as soon as it is April 2 somewhere on the planet. (This would currently be at UTC+14, matching the Line Islands.)
I can't see a way to use AoE to derive a global start time. Is there an equivalent to AoE (a standardized semantic timezone) that tracks the global start time?
Notes:
Hardcoding UTC-12 and UTC+14 is the simple answer for the modern day. But I'm looking for semantic timezones that would be updated if the values changed (and not reference non-existent historical datetimes).
I thought I'd seen Etc/AoE in the tz database but this is not the case.
References:
AoE
UTC-12:00
UTC+14:00
[1] The Anywhere on Earth (AoE) timezone represents the moment a datetime expires "anywhere on Earth". It currently matches time at Howland Island (UTC-12). If a UTC-13 timezone were invented, it would be updated to track that.
As far as I could understand, AoE is not a timezone as defined by IANA (AFAIK, a list of all offsets from some geographic region during history).
It's more like a "concept", an idea of a specific date being valid in any place on earth. As you said, this notion of "being valid" will change if more timezones are created or removed.
I don't even know if date/time API's can properly handle AoE automatically - maybe I should study more. But my conclusion is that the only way to achieve your goal is to check manually:
you could check all available timezones and see if the date is valid there, comparing to the current date/time at that zone
you could configure the UTC+14 as the offset to be compared, and make some scheduled job (daily/weekly/every-time-IANA-publishes-a-new-version?) to check all zones and set the correct one (with the biggest offset?). You must also take care if this zone has Daylight Saving changes, because the offset will change as well (and what to do with overlaps, when clocks shift 1 hour back and a local time may exist twice?)

ActiveRecord's weird timezone handling when Daylight Saving Time changes

I have an application providing agenda functionalities.
Disclaimer: I really love Rails and AR's functionalities, this is just meant to ask how can I exploit it functionalities better the next time.
Since it has to be used by a european team it has been developed using +0200 timing informations. I know that the timezone stuff is handled by AR and the base data is always stored in UTC.
The issue I get (but I already solved, just wanted to get some feedback to think it better the next time) is that when I store a new appointment I also enforce "+0200" at the end of the DateTime.parse call (es. DateTime.parse("#{day} #{hour} +0200") and then I set it as record attribute. Of course 10:00 gets stored as 08:00 inside the data layer, and that's fine.
Then when I retrieve that data using the configured AR timezone (Rome for instance) using something like #appointment.start_at it correctly gets converted back when we are under the CEST daylight time. Issues start happening when start_at are set to be CET (+0100) dates (but I always store it inside the database enforcing CEST +0200).
Inside the database start_at is always the same, so the UTC representation is always 08:00 when saving an appointment with 10:00 but the AR conversion uses the wrong daylight conversion (CET).
I know I could skip this by simply working all on UTC so I don't have to carry out any consideration about daylight savings times, but it seems a bit messy that AR itself is not able to remember somehow that I stored it while CEST is running.
When performing queries I do the same as when storing, so I append "+0200" to all DateTimes, and all works back again, but when displaying I need to check whether the TimeZone is "CET" or "CEST" and add a +1.hour to CET (otherwise it results the appointment has been signed 1 hour before than the intended hour).
Is it right I should handle this by myself?
Shouldn't be AR able to perform this kind of check since it wraps the data-layer?
How should I design an application the next time to avoid this kind of issue while still using local timezones? (as I said using UTC may also not be applicable by some requirements)
I thought I should change "+0200" with "in_time_zone" the next time, but I also allow users to write by hand an hour to search, and of course this will always be the same time either it is "CET" or "CEST" and of course I cannot enforce users to write following the UTC format.
Thank you,

Datetime and Time Zones - OpenERP 7

I'm keeping the current date in a model using a datetime field in which I am indicating default to take the current date as a value.
_defaults = {
'f_inicio' : lambda *a: datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
}
Assuming that the current date is '07/10/2013 17:24:05 ', in the view is the date '07/10/2013 12:24:05' and rectified in the database and the date is '07/10/2013 17:24:05'; gather that this subtracting five hours. The user can set the time zone 'America/Bogota', Colombia is in the region (GTM - 5:00). But do not understand how to properly show when the user since I get a totally different value that should show. Apparently this taking as 'GTM 0' the GTM Colombia. Taking the approximate date create_date field that should have given me as default is '2013-10-07 22:24:05.384'.
Anyone have any idea what may be happening, really appreciate any help on this issue that is driving me crazy.
This drived me too crazy in the past. This is a real simple issue.
The date stored in the database is UTC (GMT-0) timezone. Assume that the person is set with timezone GMT - 5:00, then while storing the value to the database, the date will be added with 5 hrs (exactly 5, not little more or little less) and thus we get the UTC time to store into the database. Now when displaying the same it will check for the users timezone and it finds that its GMT - 5:00 so the database time will be subtracted with 5 (again exactly 5, not little more or little less) and displayed the user.
This will be great for system which is used in different timezones. So the understanding is the input is taken in the user's timezone stored in UTC(GMT-0) and displayed to user's timezone (even if the user viewing is in the different timezone the time will be accurate to their timezone)
Note: if the user is not set with the timezone the browsers timezone is considered and will be used with the warning icon on the top corner
That's it. Hope this gives u better clarity!!

Time zone for Firebase.ServerValue.TIMESTAMP

It appears that when I use Firebase.ServerValue.TIMESTAMP currently, it is using PDT (I assume that will be changing to PST in the fall).
Is there a way to get this in UTC instead of PDT?
Firebase timestamps are always stored as milliseconds since the epoch (midnight of 1/1/1970 in UTC). This is the same way that dates work in Javascript and many other languages. This is a timezone-agnostic way of representing time.
Generally speaking, timezone only plays a role in how a time is displayed to a user, not in how it's represented under-the-hood. Firebase timestamps are no different.
So, if you construct a JS date object using a timestamp created by Firebase.ServerValue.TIMESTAMP, it will automatically have the same timezone as the machine on which it is being displayed.

Rails timezone and Daylight saving time

for a while I´m trying to understand how this timezone times will work, and I had a question:
Today in my country, we are in Daylight saving time (GMT-2).
So the user of my application enter a time, like 11:00AM and post the form.
Far as I know, rails will convert this date to UTC and save in the database (mysql in my case), like: 01:00PM UTC.
When I recover that record, I had to convert to local time to display. Ok?
My question is, lets suppose that this date/time represents a date/time in future, when my country gets out from summer time (GMT-3). Rails will save 01:00PM UTC? Today, in Daylight saving time, how will be the local time? And in the future, how will be this local time?
Basically, I always need to display to user 11:00AM.
thanks.
There are several places where timezone can come into play: the operating system (or probably user account) default setting, the database server, Rails environment.rb.
The key is to make sure all dates are stored with UTC time zone, then displayed in whatever your local timezone is. It sounds like you're doing that.
So your question seems to boil down to "if it's Daylight time, I want to offset by -3 hours, else offset by -2 hours". The Rails time extensions let you determine your current offset like Time.zone.now.utc_offset, and Time#dst? tells you if it's Daylight Savings Time with those two you can conditionally subtract the extra hour (3600 hundred seconds).
7 months after you asked, but perhaps skip_time_zone_conversion_for_attributes= will help - it tells AcitveRecord not to convert timezones on storage or retrieval. See ActiveRecord Timestamp which shows the example:
class Topic < ActiveRecord::Base
self.skip_time_zone_conversion_for_attributes = [:written_on]
end

Resources