Skip to content

Instantly share code, notes, and snippets.

@mcmire
Created October 28, 2011 18:57
Show Gist options
  • Save mcmire/1323091 to your computer and use it in GitHub Desktop.
Save mcmire/1323091 to your computer and use it in GitHub Desktop.
Formatting dates/times in Rails 3 vs Rails 2

In Rails 2, if you wanted to define a named date/time format, the conventional way was to make an initializer which would modify the DATE_FORMATS hash that ActiveSupport mixed into Date and Time:

# config/initializers/date_and_time_formats.rb
def military_hour_to_civil_hour(hour)
  mod = (hour % 12)
  mod + (12 * (mod > 0 ? 0 : 1))
end

Date::DATE_FORMATS[:std] = lambda {|d| "#{d.month}/#{d.day}/#{d.year}" }
Time::DATE_FORMATS[:std] = lambda {|t| "#{t.month}/#{t.day}/#{t.year} #{military_to_civil_hour(t.hour):%M%p" }

To use the formatted date/time, you'd then use #to_formatted_s (aliased to #to_s) defined on Date and Time:

date = Date.new(2011, 2, 3)
date.to_s(:std)  #=> "2/3/2011"
time = Time.utc(2011, 2, 3, 4, 5)
time.to_s(:std)  #=> "2/3/2011 4:05am"

Modifying a constant monkeypatched into a Rails core class has never felt right to me, though. Fortunately in Rails 3 (*), date/time formats are now customizable via i18n, so we can now just update the locale file like so.

# config/locales/en.rb
{
  :en => {
    :date => {
      :formats => {
        # Note that a two-element array is passed to this lambda unlike before.
        # The first element is the object, the second is a hash of options.
        :std => lambda {|d,_| "#{d.month}/#{d.day}/#{d.year}" }
      }
    },
    :time => {
      :formats => {
        # Note that a two-element array is passed to this lambda unlike before.
        # The first element is the object, the second is a hash of options.
        :std => lambda {|t,_|
          military_hour = t.hour
          mod = (military_hour % 12)
          civil_hour = mod + (12 * (mod > 0 ? 0 : 1))
          "#{t.month}/#{t.day}/%Y #{civil_hour}:%M%p"
        }
      }
    }
  }
}

Using the formatted date/time is a bit different too. Instead of using #to_formatted_s, we can use I18n.translate (or I18n.t for short):

date = Date.new(2011, 2, 3)
I18n.t date, :format => :std  #=> "2/3/2011"
time = Time.utc(2011, 2, 3, 4, 5)
I18n.t time, :format => :std  #=> "2/3/2011 4:05am"

(*) This may actually be also available in Rails 2.2, I just haven't seen anything about it before...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment