About Time

As we prepare to “fall back” this weekend in the US I’ve been thinking about writing code that deals with dates and times. This is easy to get wrong and is a common cause of bugs.

Dates

The first issue is how to write dates. For example, if I write 11/03/2021 that means November Third in the US, but in other countries it might be March Eleventh. Oops.

With that in mind, I always use ISO 8601 format for dates: 2021-11-03. To me this just makes sense. The year is the biggest so it comes first, followed by the month and day. In a Rails console you can try something like this:

Date.new(2021, 11, 3)

Date.parse(“2021-11-03”)

Easy. No confusion. The order is the same in both cases.

Times

Times are easy, right? Everyone does hours, colon, minutes. Well, not exactly. Some folks like 24-hour time and some like AM / PM.

In casual conversation I use AM / PM, but in code I try to always use 24-hour time. That way you immediately know if the time is before or after noon. For example, 1:00 could be AM or PM, but 01:00 and 13:00 are clear. Back to Rails, it looks like this:

Time.parse(“2021-11-03 13:00”)

But there’s still one piece missing.

Time Zones

The bane of programmers everywhere. The dreaded time zone.

In my experience things usually default to UTC time. I’ve never seen a database that stored times in a different time zone. In Rails you can configure the default time zone:

# config/application.rb

config.time_zone = “UTC”

You can parse times in other time zones. You can also change the time zone on existing objects. This is useful when you want to display a time in the user’s time zone.

t = Time.parse(“2021-11-03 13:00 CDT”)
=> “2021-11-03 13:00:00 -05:00”


t.in_time_zone(“America/New_York”)
=> “Wed, 03 Nov 2021 14:00:00 EDT -04:00”

Notice how the format is different after I changed the time zone? That’s because it also changed the class of the object.

t = Time.parse(“2021-11-03 13:00 CDT”)
=> “2021-11-03 13:00:00 -05:00”

t.class
=> Time


t.in_time_zone(“America/New_York”).class
=> ActiveSupport::TimeWithZone

You can format the output however you like, these are just the defaults. Note that setting the time zone in Rails only changes the way the time is displayed. The actual value remains the same.

t = Time.parse(“2021-11-03 13:00 CDT”)
=> “2021-11-03 13:00:00 -05:00”

t.to_i
=> 1635962400


t.in_time_zone(“America/New_York”).to_i
=> 1635962400

Comparisons between times in different time zones will work as expected. 13:00 central time is equal to 14:00 eastern time.

I’m on call for work this weekend. Look for a follow-up post on Monday talking about everything that broke on Saturday night.