Keeping Your Dates and Times DRY with to_formatted_s

Raw dates and times in Ruby are not too user-friendly!

The default times and datetimes in rails are pretty unattractive and contain more information than we usually need to display.

For example:

@user.created_at # => Mon, 18 May 2009 19:51:51 +0100

A useful way around this is to use the strftime() method to specify the format of the date or time.

So instead, we can use:

@user.created_at.strftime("%d %b %y") # => "18 May 09"

This way we only display the information we want to.

Specifying time with strftime() throughout an entire app is not ideal though; apart from anything else it’s not DRY. Also, if your strftime formats are quite elaborate, the chances of you mistyping them and leaving inconsistencies throughout your app are pretty high.

Enter: to_formatted_s()

to_formatted_s() is a method available to classes Date, Time and DateTime which converts the time format to a more practical format.

@user.created_at.to_formatted_s(:time) # => "20:06"

The default format is :default but you can specify any of the other pre-set formats by simply passing the name of the format as a parameter.

Classes Time and DateTime share these formats:

DATE_FORMATS  =  {
:db => "%Y-%m-%d %H:%M:%S", # => "2009-05-18 20:03:48"
:number => "%Y%m%d%H%M%S", # => "20090518200545"
:time => "%H:%M", # => "20:06"
:short => "%d %b %H:%M", # => "18 May 20:06"
:long => "%B %d, %Y %H:%M", # => "May 18, 2009 20:07"
:long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") }, # => "May 18th, 2009 20:07"
:rfc822 => "%a, %d %b %Y %H:%M:%S %z" # => "Mon, 18 May 2009 20:08:25 +0100"
}

and the Date class has these formats:

DATE_FORMATS = {
:short => "%e %b", #=> "18 May"
:long => "%B %e, %Y", # => "May 18, 2009"
:db => "%Y-%m-%d", # => "2009-05-18"
:number => "%Y%m%d", #=> "20090518"
:long_ordinal => lambda { |d| d.strftime("%B #{d.day.ordinalize}, %Y") }, # => "May 18th, 2009"
:rfc822 => "%e %b %Y" # => "18 May 2009"
}

(RFC822 is the standard for the format of ARPA internet text messages.)

As well as using these default time formats, you can also set your own formats that can be used throughout your entire app.

To do this, simply expand on the default DATE_FORMATS.

First, create a new file: config/initializers/datetime_formats.rb and add the following:

Date::DATE_FORMATS[:my_format] = lambda { |t| t.strftime("#{time.day.ordinalize} of %B, %Y") }
Time::DATE_FORMATS[:my_format] = lambda { |t| t.strftime("#{time.day.ordinalize} of %B, %Y") }

If you’re setting the same format(s) on both Date and Time then this can be further simplified to:

[Time, Date].map do |klass|
  klass::DATE_FORMATS[:my_format] = lambda { |t| t.strftime("#{time.day.ordinalize} of %B, %Y") }
end

Now all you have to do is call

<%= @user.created_at.to_formatted_s(:my_format) %>

or even simpler:

<%= @user.created_at.to_s(:my_format) %>

Much DRYer! :)

Jo Hund has put together a great cheat-sheet for stfrtime formats, it’s available here as a .pdf download.

Written by

Photo of Gavin Morrice
Gavin Morrice

Software engineer based in Scotland

Work with me

Need help with some code?

In my free time, I like to help people improve their code and skills on Codementor.
Contact me on Codementor