Telling Time with Ruby
Ask any Ruby developer what led them to embrace the language, and most will praise its "beauty," comparing Ruby's syntax to a eloquent poem or piece of art. Admittedly, this sort of aggrandization used to elicit a sneer from yours truly, although at that point I'd never actually looked into the language to determine what all of the fuss was about. That is, until one day a single line of Ruby code caught my attention while surfing online:
Made possible through the Active Support gem, when executed, this line of code will return the date and time occuring exactly seven days prior to its execution. Today being Valentine's day, executing this code now will return:
Thu Feb 14 11:10:26 -0500 2008
Although I'm not yet prepared to place the language alongside the Picasso's and Chagall's hanging in the Met, since encountering this mere line of code I've been utterly hooked on the language. But, this example is just the tip of the iceberg when it comes to Ruby's intuitive date and time parsing and calculation capabilities. In this tutorial, I'll introduce you to some of the language's temporal features, helping you to turn what is traditionally a frustrating aspect of programming into something that's fun and productive.
An Exploration of Time
The best way to become familiar with Ruby's time features is to fire up the interactive Ruby shell (IRB) and start experimenting. To do so, open a terminal and execute irb. Start simple and determine the current date and time, done with the DateTime class' now method:
irb>DateTime.now => Thu, 14 Feb 2008 13:19:21 -0500
You can take advantage of a number of methods to learn more about the current time and date:
irb>DateTime.now.year => 2008 irb>DateTime.now.month => 2 irb>DateTime.now.day => 14 irb>DateTime.now.hour => 09 irb>DateTime.now.min =>32 irb>DateTime.now.sec =>59
You also can use the DateTime class to learn more about a given date's surroundings. For instance, what will the date be four years from now, and what was it four years ago?
irb>DateTime.now.years_since(4) => Tue, 14 Feb 2012 13:37:42 -0500 irb>DateTime.now.years_since(4) => Sat, 14 Feb 2004 13:37:42 -0500
You also can use DateTime's methods to calculate the beginning of the current month and beginning of the current quarter:
irb>DateTime.now.beginning_of_month.to_date => Fri, 01 Feb 2008 irb>DateTime.now.beginning_of_quarter.to_date => Tue, 01 Jan 2008
How about determining the current day of the week? You can use the strftime method to determine this and so much more. strftime works similarly to PHP's strftime() function, accepting a time, bject, and formatting it according to a set of directives. The list of directives is too long to list here, so refer to the previous link for a complete breakdown. Returning to the objective, use strftime to learn more about today's weekday:
irb>DateTime.now.strftime("%A") => Thursday
Remember the somewhat user-unfriendly string returned by Time.now? What if you wanted to recreate the current date/time in a friendlier form? You can use several of strftime's directives to create whatever format you please:
irb>DateTime.now.strftime("%b %d, %Y") => "Feb 14, 2008" irb>DateTime.now.strftime("Today is %A, %I:%M%p") => "Today is Thursday, 12:21PM" irb>DateTime.now.strftime("%Y-%m-%d") => "2008-02-14"
Calculating the Number of Days Between Two Dates
The previous examples are all interesting, but programmers don't always live in the here and now. Often, they're tasked with working with dates residing well into the future and the past. For instance, what if you wanted to calculate the distance between Memorial Day and the Fourth of July?
irb>memorial = DateTime.new(2008,05,31) => Sat, 31 May 2008 00:00:00 +0000 irb>fourth = DateTime.new(2008,07,04) => Fri, 04 Jul 2008 00:00:00 +0000 irb>days = (fourth - memorial).to_i => 34
Never Be Late Again with Chronic
Ruby's built-in time and date parsing and calculation capabilities are great, but some really interesting work has been done by the community to really enhance the ability to perform some powerful temporal calculations. One of my favorite such projects is Chronic, a date/time parser that makes it possible to reference dates in a fascinating and natural fashion. Install Chronic through Ruby's gem system:
%>gem install chronic
Once installed, fire up irb again and retrieve the Chronic library: