Ruby Gotcha: Setting default Date, Time and DateTime

If you’re using dates, times and datetimes throughout your appliacation, you might find yourself wanting to specify a default format for each. The default formats come back as follows;

[1] pry(main)> Date.today.to_s 
=> "2014-10-28" 
[2] pry(main)> Time.now.to_s 
=> "2014-10-28 13:07:15 +0000" 
[3] pry(main)> DateTime.now.to_s 
=> "2014-10-28T13:07:19+00:00"

In a commercial web application, it won’t be long before you have a manager knocking on your door asking you to change this format to something a little more human-friendly. It is true that you do have a “strftime” method that allows you to do this:

[1] pry(main)> Time.now.strftime("%H:%M") 
=> "13:41"

But if you’re thinking like a programmer, you will not want to be copy/pasting that format all over your application, you’ll want to change it in one place and for that change to be adopted application-wide. In a rails application you may reason that this could be done in an initializer:

# config/initializers/time_formats.rb 
Time::DATE_FORMATS[:default] = "%H:%M" 
Date::DATE_FORMATS[:default] = "%e %b %Y" 
DateTime::DATE_FORMATS[:default] = "%e %b %Y"

Nice and tidy! So let’s check that out in the console…

[1] pry(main)> Time.now.to_s 
=> "13:45" 
[2] pry(main)> Date.today.to_s 
=> "28 Oct 2014" 
[3] pry(main)> DateTime.now.to_s 
=> "13:45"

Oh dear! Although the Time and Date formats have worked correctly, it appears the DateTime format is broken and is only giving us back the time! This is the gotcha – a datetime will cast its value to a Time and return THAT value, with its associated default format. You can see this from the source code: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/DateTime.html#method-i-to_s

dt_lite_to_s(VALUE self) { 
  return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx); 
}

So how do we get around it?

 Solution

There are probably a whole bunch of solutions to this issue, but one is to use one of the more unique features of ruby and monkey-patch the DateTime class:

 
# config/initializers/time_formats.rb 
Date::DATE_FORMATS[:default] = "%e %b %Y" 
Time::DATE_FORMATS[:default] = "%H:%M" 
DEFAULT_DATETIME_FORMAT = "%e %b %Y %H:%M" 
class DateTime 
  def to_s 
    strftime DEFAULT_DATETIME_FORMAT 
  end 
end

Viola

[1] pry(main)> Time.now.to_s 
=> "13:52" 
[2] pry(main)> Date.today.to_s 
=> "28 Oct 2014" 
[3] pry(main)> DateTime.now.to_s 
=> "28 Oct 2014 13:53"

Would be interested to hear about other solutions to this gotcha if anyone else has any ideas.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s