ISO8601 is a simple implementation of the ISO 8601 (Data elements and interchange formats — Information interchange — Representation of dates and times) standard.

Build status

Build Status Dependency Status Gem Version

Supported versions

  • MRI 2.x
  • RBX 2

Check the changelog if you are upgrading from an older version.


Check the rubydoc documentation.

Comments about this implementation

Duration sign

Because Durations and DateTime have a substraction method, Durations has sign to be able to represent negative values:

('PT10S') -'PT12S')).to_s  #=> '-PT2S'
('-PT10S') +'PT12S')).to_s #=> 'PT2S'

Fractional seconds precision

Fractional seconds for ISO8601::DateTime and ISO8601::Time are rounded to one decimal.'2015-02-03T10:11:12.12').second #=> 12.1'T10:11:12.16').second #=> 12.2

Differences with core Date, Time and DateTime

Core Date.parse and DateTime.parse doesn't allow reduced precision. For example:

DateTime.parse('2014-05') # => ArgumentError: invalid date

But the standard covers this situation assuming any missing piece as its lower value:'2014-05').to_s # => "2014-05-01T00:00:00+00:00"'2014').to_s # => "2014-01-01T00:00:00+00:00"

The same assumption happens in core classes with .new:,5) # => #<DateTime: 2014-05-01T00:00:00+00:00 ((2456779j,0s,0n),+0s,2299161j)> # => #<DateTime: 2014-01-01T00:00:00+00:00 ((2456659j,0s,0n),+0s,2299161j)>

The value of second in core classes are handled by two methods: #second and #second_fraction:

dt = DateTime.parse('2014-05-06T10:11:12.5')
dt.second # => 12
dt.second_fraction # => (1/2)

This gem approaches second fraction using floats:

dt ='2014-05-06T10:11:12.5')
dt.second # => 12.5

Unmatching precison is handled strongly. Notice the time fragment is lost in DateTime.parse without warning only if the loose precision is in the time component.'2014-05-06T101112')  # => ISO8601::Errors::UnknownPattern
DateTime.parse('2014-05-06T101112')  # => #<DateTime: 2014-05-06T00:00:00+00:00 ((2456784j,0s,0n),+0s,2299161j)>'20140506T10:11:12')  # => ISO8601::Errors::UnknownPattern
DateTime.parse('20140506T10:11:12')  # => #<DateTime: 2014-05-06T10:11:12+00:00 ((2456784j,0s,0n),+0s,2299161j)>

DateTime#to_a allow decomposing to an array of atoms:

atoms ='2014-05-31T10:11:12Z').to_a # => [2014, 5, 31, 10, 11, 12, '+00:00']
dt =*atoms)

Ordinal dates keep the sign. 2014-001 is not the same as -2014-001.

Week dates raise an error when two digit days provied instead of return monday:'2014-W15-02') # => ISO8601::Errors::UnknownPattern'2014-W15-02')  # => #<Date: 2014-04-07 ((2456755j,0s,0n),+0s,2299161j)>

Compatibility with core classes

Each ISO8601 class has a method to_* to convert to its core equivalent:

ISO8601::DateTime#to_datetime -> DateTime (it actually delegates a couple of methods from DateTime). Check lib/iso8601/date_time.rb:13.

ISO8601::Date#to_date -> Date (it actually delegates to a couple of methods from Date). Check lib/iso8601/date.rb:18

ISO8601::Time#to_time -> Time (it actually delegates to a couple of methods from Time). Check lib/iso8601/time.rb:15

ISO8601::Atom#to_f -> Float, ISO8601::Atom#to_i -> Integer



# Install Docker
$ make install
$ make test

You can alse target specific runtimes:

$ make mri-test
$ make rbx-test
$ make jruby-test


The old fashion way:

# Install a Ruby flavour
$ bundle install
$ bundle exec rspec



Please see


Arnau Siches under the MIT License