ISO8601 Dates in Ruby

ISO8601 is a standard for representing date/time information as a string. ISO8601 dates look like this: 2009-10-26T04:47:09Z.

There are a lot of good reasons to store dates in the ISO8601 format. The format is…

  • Unambiguous. There is never any question how to interpret them.
  • Human-readable. You can look at dates stored in ISO8601 and interpret them easily.
  • Widely-supported. All major programming languages have libraries for parsing and writing ISO8601 dates.
  • Sortable. If you follow a few simple rules, ISO8601 dates sort lexicographically into the order you would expect.

That last property makes ISO8601 a particularly good candidate for date/time storage in simple non-relational data stores like Amazon’s SimpleDB. Storing dates as ISO8601 lets you sort records by date in data stores which don’t support a native date/time data type – without sacrificing human-readability.

Using ISO8601 from Ruby couldn’t be simpler, if you know where to look for the tools. If you look at the Ruby Time class by itself, you won’t find any reference to ISO8601. The secret is to require the ‘time’ library:

irb(main):001:0> time = Time.now.utc.iso8601
NoMethodError: undefined method `iso8601' for Mon Oct 26 04:46:57 UTC 2009:Time
        from (irb):1
        from :0
irb(main):002:0> require 'time'
=> true
irb(main):003:0> time = Time.now.utc.iso8601
=> "2009-10-26T04:47:09Z"
irb(main):004:0> Time.iso8601(time)
=> Mon Oct 26 04:47:09 UTC 2009

Note the use of utc to convert the local time into universal time (aka Greenwich Mean). This is important if you want your time strings to be lexicographically sortable. The “Z” on the end of the ISO8601 date indicates that it is in UTC, not a local time zone.

This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.
  • http://metaclass.org/ Wilson Bilkovich

    require 'rss' works because it is requiring 'time'.
    If you just want the iso8601 support, you can go with: require 'time'

    Also, Time#iso8601 takes a handy optional argument for the number of fractional digits at the end.
    I've had to use this to interact with brittle external services, for example.

    • http://avdi.org avdi

      Thanks, I've updated the post!

  • http://metaclass.org/ Wilson Bilkovich

    require 'rss' works because it is requiring 'time'.
    If you just want the iso8601 support, you can go with: require 'time'

    Also, Time#iso8601 takes a handy optional argument for the number of fractional digits at the end.
    I've had to use this to interact with brittle external services, for example.

  • http://wideteams.com Avdi Grimm

    Thanks, I've updated the post!

  • http://twitter.com/oPaxa Тотото Сё

    What is about time periods ? How can I get format like this PT1H30M ?

    • http://twitter.com/hazula Benjamin Fleischer

      The ruby ‘time’ library only handles the xmlschema time discussed. I’m unaware of implementations of the full iso8601 spec. Perhaps one of the microformats tools uses it. see http://microformats.org/wiki/datetime-design-pattern

    • Wilson Bilkovich

      There is a gem that provides some support for this.
      gem listing: http://rubygems.org/gems/iso8601
      source: https://github.com/arnau/ISO8601

      Here’s a small session using it:
      >> require ‘iso8601′
      >> include ISO8601
      >> Duration.new(659).to_s
      => “PT659S”
      >> (Duration.new(659) – Duration.new(323)).to_s
      => “PT5M36S”

  • Kris L

    Great post regarding iso8601. I was trying to load a Time object from a YAML config file and everything else I did just returned a string representation of the date. By using the iso8601 format, YAML correctly parses it back to a Time object. :)