I ran into a little bug on DEV, so I wanted to share this post as both a bug report, and an opportunity to share how I solved the same problem in my own product recently.
The calendar events on the DEV Events pages don’t have a time zone attached to them (or maybe the wrong time zone), so they get added to the wrong time on my calendar. For example, this event is at 12pm EDT. I live in Toronto, which is EDT, but when I add it to my calendar it gets added at 4pm. I'll send this bug report via email too, in case you don't see this.
Time zones are always painful to work with. My company, preventalemon.com, deals with time zones constantly, with people setting appointments all across the US, sending out calendar events, texts and emails with appointment reminders, and more. So getting time zones right was a priority (it wasn't done right when I took over the code base, but it was my problem to solve).
My app is in Rails, but I'm sure you can take a similar approach in any MVC framework.
The first piece of advice is to ALWAYS store times in your database in UTC. Without doing that, the rest of this post is useless.
The first step was to set the time zone of the current visitor. I did this in the Application Controller, in a private method which gets called using a
around_action callback. This way every transaction on the website goes through this callback first.
around_action :set_time_zone, if: :signed_in? private # Set the time zone to use for the current action def set_time_zone(&block) #we have three types of users (admins, mechanics, customers) user = current_admin_user || current_user || current_customer # if there's a user, use their time zone, otherwise use UTC time_zone = user ? (user.time_zone || "UTC") : "UTC" Time.use_zone(time_zone, &block) end
It's worth noting here that our user's time zones are set based on their addresses. Every customer and mechanic provides an address when signing up because that's a core part of our app's functionality (we do on-demend vehicle inspections, so location is important).
Now when someone books an inspection, we create a calendar event that gets attached to an email and sent to them. For sending emails we actually have to pass in the time zone in an argument, rather than relying on the Application Controller callback, because it's done in a background job and it's outside of the controller's action.
We're using the icalendar Ruby gem. Thanks to them for their work.
def calendar_event(time_zone=Time.zone.name) cal = Icalendar::Calendar.new # Setup a bunch of data about the event. Not relevant to this post, but included for clarity. event_start = inspection_time.in_time_zone(time_zone) event_end = inspection_time.in_time_zone(time_zone)+1.hour @organizer = "mailto:email@example.com" @attendee = [customer.email, mechanic.email] @location = full_address @summary = "PAL Inspection" @description = "PAL Inspection" cal.append_custom_property('METHOD', 'REQUEST') # We create a timezone object timezone = TZInfo::Timezone.get(time_zone).ical_timezone(event_start) # We add the timezone object to the calendar event cal.add_timezone(timezone) cal.event do |e| # When setting the time of the event, we specify the time zone. e.dtstart = Icalendar::Values::DateTime.new event_start, 'tzid' => time_zone e.dtend = Icalendar::Values::DateTime.new event_end, 'tzid' => time_zone # more irrelevant data being added to the event. e.organizer = @organizer e.organizer = Icalendar::Values::CalAddress.new(@organiser, cn: 'Prevent A Lemon') e.attendee = @attendee e.location = @location e.summary = @summary e.description = @description end return cal end
And now the calendar even will be set in the correct time zone based on the location of the appointment! Time Zones are a real mind bender. The one other suggestion I can share is to ALWAYS display the time zone to the visitor, so even if you do get the zone wrong for some reason, they'll see it and hopefully make the adjustment for themselves. We had a bug where text reminders were being sent out in UTC, but thankfully because it said "9:00am UTC" in the text, people figured it out and still showed up on time until we fixed it.
I don't think any of what I've shared is new or exciting, but it's something I wish I learned about earlier, so hopefully it helps someone. If I missed something or you have questions, post in the comments and I'll get back to you between 7am EDT and 10pm EDT ;-)