Playing with Ruby Dates

One of my previous projects involved a ton of work using Flash's built in Date object. We ended up rolling our own Calendar library which was both tedious and time consuming to debug. Now that I'm digging into Ruby for my newest project, I wanted to see what features the language has to offer. So far I'm really impressed and that's after only a few hours of exploration. I'll detail some of the tricks I've learned along the way so hopefully other newcomers can benefit.

Ruby Date Object Basics

We can start off by firing up IRB and requiring the date class. Let's do a really simple example first and just generate today.

require 'date'

today = Date.today  
 => #<Date: 2012-04-28 ((2456046j,0s,0n),+0s,2299161j)>

Now lets try a bit of Ruby's sugar to generate tomorrow's date.

tomorrow = today + 1  
 => #<Date: 2012-04-29 ((2456047j,0s,0n),+0s,2299161j)> 

Pretty straightforward, right? Since there is usually more than one way to do something in Ruby we could have achieved the same results using any of the following.

today.succ  
 => #<Date: 2012-04-29 ((2456047j,0s,0n),+0s,2299161j)>

today.next  
 => #<Date: 2012-04-29 ((2456047j,0s,0n),+0s,2299161j)> 

today.next_day  
 => #<Date: 2012-04-29 ((2456047j,0s,0n),+0s,2299161j)> 

As someone on StackOverflow pointed out: Date objects are also Comparable, so you can construct a Range. If you wanted to collect every day from the previous week into an array you could do the following:

last_week = today - 7  
every_day_last_week = (last_week..today).to_a  

or...

today.downto(today - 7).to_a  

There are also some cute booleans tossed into the mix for figuring out the day of the week.

today.friday?  
 => false

today.saturday?  
 => true

How to Use Chronic

Chronic is a Ruby natural language date/time parser written by Tom Preston-Werner (@mojombo) which takes surprisingly human readable text and converts it to dates.

Covering everything that Chronic supports could take a while so definitely go check out the docs. Below is just a quick example to demonstrate how cool it is.

require 'chronic'

Chronic.parse('yesterday')  
 => 2012-04-27 12:00:00 -0700

Chronic.parse('yesterday').to_date  
 => #<Date: 2012-04-27 ((2456045j,0s,0n),+0s,2299161j)> 

Chronic.parse('last monday')  
 => 2012-04-23 12:00:00 -0700 

Chronic.parse('3 months ago this friday at 3:45pm')  
 => 2012-02-04 15:45:00 -0800

How to Use Active Support for Dates

Active Support is a library extracted from Rails which adds a ton of sugar to the Ruby language. As the author's describe it:

Active Support is a collection of various utility classes and standard library extensions that were found useful for Rails. All these additions have hence been collected in this bundle as a way to gather all that sugar that makes Ruby sweeter.

It's broken into several pieces so you can choose to load only the parts that you'll actually be using. I'm going to write an upcoming article on Active Support. For now we'll just require it all.

require 'active_support/all'

t = Date.today  
 => Sat, 28 Apr 2012

t.class  
 => Date 

You'll notice that Active Support has changed the way our date's to_s is formatted so it's more human readable. It also added shortcuts for creating Dates on either side of today.

yesterday = Date.yesterday  
 => Fri, 27 Apr 2012 

tomorrow = Date.tomorrow  
 => Sun, 29 Apr 2012

Included as well are some nice convenience booleans: past?, today?, and future?

tomorrow.future?  
 => true

If you've ever had to write a Calendar that can support weeks, especially those that straddle two different months, you'll appreciate the simplicity of the helpers Active Support adds.

today = Date.today  
 => Sat, 28 Apr 2012

today.beginning_of_week  
 => Mon, 23 Apr 2012

today.next_week  
 => Mon, 30 Apr 2012

# You can also choose to make the week start on an arbitrary day, like Sunday
today.beginning_of_week(:sunday)  
 => Sun, 22 Apr 2012

We aren't limited to weeks though. Active Support adds methods for days, months and years. For example:

today.years_ago(10)  
 => Sun, 28 Apr 2002

By extending FixNum to support additional Date methods certain operations become much more readable.

today + 1.year  
 => Sun, 28 Apr 2013

These extensions are referred to as durations in the documentation.
Which brings us back to one of our first examples of finding the date 7 days ago. With Active Support it's as easy as...

7.days.ago  
 => 2012-04-21 08:44:02 -0700

Pretty cool! Active Support adds A LOT more than just Date helpers and I'll try to cover it more in some future articles. Definitely check out the documentation (you can skip to the Date section since it's pretty immense).

Source:

http://stackoverflow.com/questions/962544/one-line-hash-creation-in-ruby http://www.developer.com/open/article.php/3729206/Telling-Time-with-Ruby.htm http://guides.rubyonrails.org/activesupportcore_extensions.html

You should follow me on Twitter here.

Photo credit