The problem: I needed to display a warning to a user if the data they were looking at was more than 90 days old.
The solution: Create a method that takes 2 dates (either DateTime or Time), and returns the number of days, or hours between them.
def self.difference_in_dates(date1, date2, unit = 1.day)
return nil if date1.nil? || date2.nil? || unit == 0
(( date1.to_time - date2.to_time ) / unit).round.abs
endThe problem was simple enough, and my tests were all passing, so I moved on to my next task.
That code has been out in production for several months, but earlier this week, a new developer told me he got an error when running the test:
NoMethodError: undefined method `to_f'
for Mon, 21 Sep 2009 14:29:38 -0500:DateTime(we’re running this in Rails 2.0.2)
I looked at the code, knowing it was working before, ran the unit tests myself, and didn’t see the issue. Now I’m on Windows and everyone else is on a mac, so as soon as I run into an issue that no one else has seen I want to prove if its a Windows problem. But wait, this test has been running in our Continuous Integration server (Hudson) for months, and no one else on the team ever had any issues with it, and the code has been working in production without any errors in the logs.
I jumped into rails script/console to see what’s up, and here’s what I found:
>> x = DateTime.now
=> Wed, 23 Sep 2009 00:00:00 +0000
>>; x.to_time
=> Wed Sep 23 00:00:00 UTC 2009
>> x.to_time.to_f
=> 1253664000.0Which is what I expected, but when I asked the other developer to run that same instruction, he got an error.
>> DateTime.now.to_time.to_f NoMethodError: undefined method `to_f' for Mon, 21 Sep 2009 14:29:38 -0500:DateTime
What’s up with that? We’re running the same code, and all of our libraries are the same version. Looking at the date value in his error, I saw the timezone, and decided to try this variation locally:
>> x = DateTime.parse("2009-09-21T14:29:38-0500")
=> Mon, 21 Sep 2009 14:29:38 -0500
>> x.to_time.class
=>; DateTimeSo I’m gathering that when there is a timezone and you ask DateTime.to_time, its just going to give you back a DateTime.
I wasn’t expecting this, and its exactly why my code was failing, because sometimes the DateTime.to_time will return just a DateTime object. The Rails 2.0.2 docs do state this:
to_time() Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class If self has an offset other than 0, self will just be returned unaltered, since there’s no clean way to map it to a Time
Ok, so I guess I have no excuse, its written right there in the docs, but I guess I, didn’t really look at the docs for the to_time method, or if I did, I didn’t really get what it was telling me. Either way I have a problem that isn’t going to change.
When I asked my colleagues at Pathfinder, they all said “Why do you need to do that?” and “couldn’t you find a gem or plugin that does that already?”
Which is a solid point. If you are doing something as common as checking for the difference between two dates you should expect to see either some straight code examples of the best way to do it, or a plugin or gem that solves that problem. I’ll need to dig into this a little further, but for the moment I simply updated the code to:
def self.difference_in_dates(time1, time2, unit = 1.day)
return nil if time1.nil? || time2.nil? || unit == 0
(( time1 - time2) / unit).round.abs
endand I looked through the places I was using this code and made sure I only passed in a Time object, so now I’ve ‘fixed’ the bug so that the tests don’t fail for anyone else, and I’ve bought myself some time to figure out what’s the best course of action.
But I’m still curious why DateTime.now behaves differently depending on OS? What’s going on there?
I jumped on to our build server (CentOs) and ran DateTime.now, and see no timezone, and that’s why the tests don’t fail there.
I jumped over to my heroku server and saw that DateTime.now includes a timezone.
Wondering what the os was I ran:
`uname -sr`.chomp.strip "Linux 2.6.18-xenU-ec2-v1.0" >> `cat /etc/issue.net` => "Debian GNU/Linux 4.0"
So what dictates the Date and Time setup? Is it purely an OS thing, or is it just a component of how time is setup on the server?
I jumped over to another Debian box, and there DateTime.now doesn’t include the timezone, so now I’m thinking that its not as simple as just the OS, but something else. (please someone, enlighten me!)
Conclusion: Don’t be an idiot
I did a few things wrong here, and I deserve to be flamed for it:
- Read the docs, understand the code you are relying on. In most cases, ruby and rails just does what you’d expect, but its still worth reading into, even when things seem to be working just fine.
- If the problem you are trying to solve seems common, google around, ask others what they have done, dig into the framework, etc. Assume you aren’t the first to run into it.
- If it seems that what you are doing isn’t common, or isn’t handled in the frameworks/libraries you are using, perhaps it means you are looking at the problem the wrong way and there is another, simpler solution out there.
- Test your assumptions. I will say that at least I had tests that covered my assumptions, and failed when they weren’t true. I may not have written the best solution, but at least it worked on every system we deployed it to, and never failed in production


I’d say it might have something to do with local time being set in the OS (ie: timezone configured for the particular server). But that’s just guessing.
Looks like you misescaped some of that information (code blocks number 3 and 5).
Thanks for pointing out that the escaping was wrong, I guess there is a difference between our pre and pre lang=’ruby’ tags.