Using XDate & Moment.js to Solve Daylight Savings Time (DST) Bugs with Adam Shaw of FullCalendar
In A Comedy of Errors, we talk to engineers about the weirdest, worst, and most interesting application and infrastructure issues they’ve encountered (and resolved) over the years. This week we hear from Adam Shaw, creator of FullCalendar, an open source jQuery plugin that provides a completely customizable drag & drop event calendar (and also has 7500 stars on GitHub).
Before we get into the biggest bugs I’ve encountered with FullCalendar, I think it’s worth noting that FullCalendar itself came out of what I’d consider an error. Several years ago I co-founded a company that was accepted to Y-Combinator; it was a website building application similar to Wix or Weebly, both of which were also just getting started. My co-founder and I had moved to Boston — because that’s where YC was at the time — and were working really hard. Then one day Paul Graham emails us asking for demo of where we were at with things.
It did not go well. This was the first time he’s seen the product thoroughly, front to back, and when we finished he essentially just face-palmed and said, “I’m trying to remember why I liked you guys in the beginning. Why I accepted you. This is terrible.” If you think about your idol in front of you, in person, critiquing your work and telling you you’re terrible — it wasn’t a good feeling.
Though we adapted and made a lot of changes, it ultimately didn’t work out. As my co-founder and I parted ways, the software we had built was going to be deleted, never run on any servers. But there was one piece of it that I thought was interesting and potentially usable, and that was the event scheduling feature.
I decided to take the code and package it up, spend an hour or two writing some quick documentation, and then throw it up on GitHub. It was going to be a resume item, nothing beyond that. But it started getting lots of followers and I was like, “how does anyone know about this?” Then I noticed that the creator of jQuery, John Resig, had discovered it and tweeted about how much he liked it. So I was getting a ton of traffic from the creator of the core technology I was using, which was pretty awesome and a nice feeling post-Paul Graham.
I continued to develop it over the next few years just as a hobby, and then it eventually grew into a paid offering which eventually grew into a company. Which brings us here discussing bugs I’ve encountered building it.
It’s hard to make catastrophic bugs with FullCalendar. Normally, if someone encounters a bug, they can just downgrade to the most recent version that works. As a result I have a fairly stress-free time managing the company because there aren’t many fires I need to put out.
Which isn’t to say I haven’t had my share of embarrassing bugs. The big problem areas are time zones and time changes. I’m confident I encountered every single bug in any way related to Daylight Savings Time in the first two years of building FullCalendar. You know the deal, you gain an hour, you lose an hour. It’s sort of a bummer for programmers because time is not completely uniform across the year, and it’s hard to test because you have to change your computer to be in different time zones, and every time zone has different Daylight Savings hours.
In order to render the typical month view that everyone is familiar with, you have to start with the first day of the month, which means some of the previous month’s days might be visible. You need to do some “date math” to back up into the previous month, to where the first visible day of your month begins. Then you have to iterate forward one day at a time until you get to the end of the month, and then maybe go into the next month a few days. There is a lot of simple date arithmetic that you need to do, like adding or subtracting a day here and there.
So you have to iterate from day to day, but the thing about Daylight Savings Time is that sometimes depending on the time zone, midnight does not exist. It skips back to 11pm the previous day, or skips forward to 1am the next day.
Sometimes we’d have a bug when we added a day, and it ended up being 1PM the next day instead of AM, skipping those 12 hours. But the real error case was if instead of turning to 11PM the previous day, it ended up being 11PM of the same day, because you haven’t really moved a day yet. Well, then it would round down to that day and iterate another day. There were two big side effects of this bug:
One would be that the entire month view of users’ calendars would be all of the same day, all of March 3rd for example, every day of the month would be March 3rd. Which is really only good if you had a great March 3rd and are looking to get into a Groundhog’s Day type of situation with it.
The other, worse side effect was that the calendar could get stuck in an infinite loop of the same day and just freeze the user’s browser tab. You might call this one the current-date-cursor-falling-into-the-Daylight-Savings-Time-witching-hour bug. Maybe.
After dealing with every DST bug possible in the first two years of product, I eventually decided to do a rewrite of that internal system and start using a third party library instead to handle all of it. Initially, I wanted to create and use my own. I had collected so much knowledge from dealing with all these date bugs I created my own date library utility. A lot of people started using it, and still continue to do. It’s called XDate. But then Moment.js launched soon after and became really popular, people were really excited about it. And it’s definitely worked well for me.
I had a hard decision to make: Do I use my own library that I implemented, or go with what most people are using? On one hand I thought, I’ve spent all this work and I’m not even using it. But on the other hand, now I don’t have to maintain all this date functionality and I can leave it to some other capable developer. It was a little disappointment mixed with reassurance that the future would be better. And honestly, it was the best decision I ever made because all those problems just went away. It’s nice to know I don’t have to do tackle every single problem myself.