On Date/Time/DateTime in Ruby, and why they suck

Sun 18 July 2010

Yeah, there, I said it - this is a stupid situation for a language to be in. The concepts of Date, Time, and DateTime are all pretty well related - Date is a point in Time, DateTime is a really nice representation of Date and Time mashed together.

In a world that actually makes sense, you'd be able to easily convert between these types (e.g: DateTime should be able to easily convert over to a Time object). Some people might suggest patching the aforementioned classes (like Rails does, for parsing relative dates), but this just feels like an incredibly hacky solution.

Now, normally, I'm not much of a Ruby guy, give me Javascript any day. However, there are a lot of awesome projects written in Ruby, and it's hard to deny that they've easily got the best packaging solution for any language. As it so happens, earlier this week I was hacking on a little Sinatra side project. DataMapper was my ORM of choice here, because it's just so beautifully plug and play.

In the example app we'll look at, it's your basic Post/Comment scenario. For each Post/Comment, we want to be able to render the relative time ago that the item in question was submitted (e.g, "16 hours ago", etc). Rails has conventions for this baked in by default (because they, y'know, enjoy polluting namespaces, go figure). When you're outside of Rails and want to do this, it's somewhat more difficult.

Originally I started by storing the creation time as DateTime; makes sense, we should be able to convert this to Time to do easy comparisons against Time.now, right?

Well, uhh, no. Definitely not that simple. After some digging around, I discovered the dm-types gem, which adds some extra types to DataMapper. One of these types is known as EpochTime, which is (you guessed it) the time since Epoch that the entry was created.

With that, we can pretty much stay within the realm of Time. Ripping apart ActionView gives us a good base to work with on the act of getting a relative string; putting it all together, we get the following Sinatra app (two files - the main Sinatra app, and our custom date_helper library).