Instantly share code, notes, and snippets.

pixeltrix/time_vs_datatime.md Last active Jul 16, 2019

When should you use DateTime and when should you use Time?

When should you use DateTime and when should you use Time?

It's a common misconception that William Shakespeare and Miguel de Cervantes died on the same day in history - so much so that UNESCO named April 23 as World Book Day because of this fact. However because England hadn't yet adopted Gregorian Calendar Reform (and wouldn't until 1752) their deaths are actually 10 days apart. Since Ruby's `Time` class implements a proleptic Gregorian calendar and has no concept of calendar reform then there's no way to express this. This is where `DateTime` steps in:

``````>> shakespeare = DateTime.iso8601('1616-04-23', Date::ENGLAND)
=> Tue, 23 Apr 1616 00:00:00 +0000
>> cervantes = DateTime.iso8601('1616-04-23', Date::ITALY)
=> Sat, 23 Apr 1616 00:00:00 +0000
``````

Already you can see something's weird - the days of the week are different, taking this further:

``````>> cervantes == shakespeare
=> false
>> (shakespeare - cervantes).to_i
=> 10
``````

This shows that in fact they died 10 days apart (in reality 11 days since Cervantes died a day earlier but was buried on the 23rd). We can see the actual date of Shakespeare's death by using the `gregorian` method to convert it:

``````>> shakespeare.gregorian
=> Tue, 03 May 1616 00:00:00 +0000
``````

So there's an argument that all the celebrations that take place on the 23rd April in Stratford-upon-Avon are actually the wrong date since England is now using the Gregorian calendar. You can see why when we transition across the reform date boundary:

``````# start off with the anniversary of Shakespeare's birth in 1751
>> shakespeare = DateTime.iso8601('1751-04-23', Date::ENGLAND)
=> Tue, 23 Apr 1751 00:00:00 +0000

# add 366 days since 1752 is a leap year and April 23 is after February 29
>> shakespeare + 366
=> Thu, 23 Apr 1752 00:00:00 +0000

# add another 365 days to take us to the anniversary in 1753
>> shakespeare + 366 + 365
=> Fri, 04 May 1753 00:00:00 +0000
``````

As you can see, if we're accurately tracking the number of solar years since Shakespeare's birthday then the correct anniversary date would be the 4th May and not the 23rd April.

So when should use you use `DateTime` in Ruby and when should you use `Time`? Almost certainly you'll want to use `Time` since your app is probably dealing with current dates and times and it has support for timezones (system/local and utc), whereas `DateTime` just has offsets from UTC. However, if you need to deal with dates and times in a historical context you'll want to use `DateTime` to avoid making the same mistakes as UNESCO. If you also have to deal with timezones then best of luck - just bear in mind that you'll probably be dealing with local solar times, since it wasn't until the 19th century that the introduction of the railways necessitated the need for Standard Time and eventually timezones.

neerajdotname commented Jun 2, 2015

 This episode of 99 % invisible goes into the history of calendar if anyone is interested.

pawlik commented Jun 6, 2015

 👍 cool story :D thanx

prestoncopeland commented Jun 7, 2015

 This is very interesting. Thanks for taking the time to write it! I recently wrote a post for beginners about the basics of displaying a date with Ruby on my blog http://threemonthcoder.com; it's really neat to read about some advanced subtleties on the same topic!

urkle commented Jun 10, 2015

 In your final example you state Shakespeare's birth, that should be death.
Owner Author

pixeltrix commented Jun 11, 2015

 @urkle Shakespeare was born and died on the same day (probably - he was baptised on the 26th). The 23rd is accepted as the anniversary of his birth and I was illustrating the fact that the celebrations are on the wrong day, whether that's his birth or death 😄

Rio517 commented Jun 11, 2015

 One should also be mindful of preformance differences that might crop up. ``````> require 'date' > require 'benchmark' > Benchmark.bm do |bm| > bm.report('DateTime:') do > n1 = DateTime.now > n2 = DateTime.now > 1_000_000.times{ n1 < n2 } > end > bm.report('Time: ') do > n1 = Time.now > n2 = Time.now > 1_000_000.times{ n1 < n2 } > end > end # Using ruby 2.2.0 w/ IRB user system total real DateTime: 0.180000 0.000000 0.180000 ( 0.181002) Time: 0.190000 0.000000 0.190000 ( 0.191819) # Using ruby 2.2.0 w/ rails 4.2 console user system total real DateTime: 0.540000 0.000000 0.540000 ( 0.603581) Time: 2.190000 0.500000 2.690000 ( 2.692820) ``````

callenb commented Jun 12, 2015

 Thank you. This has given me more understanding about `Time` being more appropriate for my Workpattern gem. I have been writing Workpattern using `DateTime`. It defines working and non-working time so public holidays, weekends and vacations can be defined as non-working and calculations take that into account. This is the kind of thing needed to calculate a project network like Microsoft Project or Primavera P6 does. I work in project management in Oil & Gas at the moment - coding is a hobby. These calculations are about the future and very recent past, so I have been re-writing my gem to use `Time`. This prompted by a question on rogues parley. I chose `DateTime` through ignorance, thinking `Time` just did time!! `Time` should also allows the gem to handle daylight saving time, though how i deal with two 1:00 am on the same day will be challenging.

bobbrez commented Aug 14, 2015

 Thanks @pixeltrix @neerajdotname I was just listening to that episode before reading this.

fatuhoku commented May 26, 2016

 Great write-up thanks. Really important!

assoftrefinery commented Jul 25, 2016 • edited

 Cervantes was spanish, not italian. And now he is universal :P