Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customizing datetime format in en.yml in Rails 3

According to documentation at http://guides.rubyonrails.org/i18n.html#adding-date-time-formats, the best way to ask for specific formats for a date is to define them in /config/locales/en.yml. I've copied and pasted this file: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml to my locales directory.

I've made a few changes (asterisks for emphasis only):

"en-US":
  date:
    formats:
      default: "%Y-%m-%d"
      **short: "short %b %d"**

and

time:
    formats:
      default: "%a, %d %b %Y %H:%M:%S %z "
      **short: "short %B %d, %Y"**

And in my partial:

<%= l item.create_date, :format => :short %>

where create_date is a datetime row in my database of items.

I've restarted my server but am still getting a date formatted like this: 15 Mar 00:00

I have a feeling that it is because i'm using neither a date or a time. I can't find the definition of "short" or "long" for datetime. I tried adding it to this file by adding this code:

datetime:
    formats:
      short: "short %B %d, %Y"

no luck. What am I missing. I feel like I'm following the instructions directly. Thanks!

like image 939
panzhuli Avatar asked Mar 20 '11 03:03

panzhuli


3 Answers

[Several months later...]

The problem is that you're trying to define a "datetime" format in en.yml, but the Rails localization code only checks for "date" or "time" (lumping "datetime" in with "time").

The offending code is in the i18n base code here, on line 53:

type = object.respond_to?(:sec) ? 'time' : 'date'

It checks if the given object can respond to "sec"; if so, it reads the "time" stuff in en.yml, if not, it reads the "date" format. No "datetime".

As Tyrael suggested, you can force it to obey your will at gunpoint via the initialization code. That will certainly work, but now you've put localization code into your initializers. That's potentially confusing and messy, IMO.

IMO, a cleaner way to do this would be to add the format you want for DateTime to the 'time' section of en.yml by specifying a different 'format', like so:

en:
  time:
    formats:
      short_datetime: %B %d, %Y
      long_datetime:  %B %d, %Y, at %r
      hammer_datetime: STOP! %B %d, %Y, is HAMMERTIME!
      # and so on... da dum... da dum...

Which you could use like this:

<%= l item.create_date, :format => :short_datetime %>

That's the approach I use meself.

But for completeness, you could also do this:

en:
  datetime:
    formats:
      default: %B %d, %Y

And then tell Rails how to read it, like this:

# In your Application Helper
def localize_datetime(dt)
  # quick-and-dirty demo... doesn't accept different format options and stuff...
  dt.strftime(I18n.t(:"datetime.formats.default", {:locale => I18n.locale }))
end
def ld(dt)
  localize_datetime(dt)
end
# or something like that...

Then use it like so:

<%= ld item.create_date %>

This would keep your localization info in your localization files, but it requires getting your hands dirty (code above doesn't do any error checking, doesn't accept parameters, etc.), and forces you to use a different function for outputting it (instead of just "l", a painfully long "ld").

Lastly (and probably leastly), we could just tell the Rails gnomes to fix that function so it allows "datetime". :)

Hope that was useful. Best of luck.

like image 55
Rick Reilly Avatar answered Nov 16 '22 20:11

Rick Reilly


I suspect the problem here is in Rails' I18n:l function. Try with this:

  1. Add below lines to one of your initializer files, e.g., config/environment.rb:

    DateTime::DATE_FORMATS[:short]="short %Y-%m-%d %H:%M:%S"
    
    Time::DATE_FORMATS[:short] = "short %Y-%m-%d %H:%M:%S"
    
    Date::DATE_FORMATS[:short] = "short %Y-%m-%d"
    
  2. modify view:

    <%= item.create_date.to_s(:short) %>
    

You can see output change to "short something".

I know it's not a perfect answer, but hope it can give you some hints(I didn't have time to check the I18n::l function).

like image 38
Tyrael Tong Avatar answered Nov 16 '22 19:11

Tyrael Tong


[several years later...]

If you want to DRY up your date formats and/or you have legacy code with to_s all over the place and don't plan to internationalize your app, you can do this:

I18n.t('date.formats').each do |key, value|
  Date::DATE_FORMATS[key] = value
end

Then just define your formats in config/locales/en.yml. Of course if you ever plan to translate your app, you'll need to change all occurrences of to_s to use the I18n.l method suggested below.

You can also use this without Rails. Just add the following before the above code:

require 'active_support/time'
I18n.load_path << 'en.yml'
like image 6
PhilT Avatar answered Nov 16 '22 20:11

PhilT