Here is my current approach for formatting time zone and date/time values. I’m using Rails 3.1.3, SimpleForm 2.0.1, and Twitter Bootstrap 2.0.1. I had some trouble finding examples of how to do this so maybe this will help someone.
Time Zone
config/locales/datetime.yml
en:
time_zone:
priority: US|Hawaii|Alaska|Arizona|Indiana
app/views/_user_fields.html.erb
<%= f.input :time_zone, :required => true, :priority => /#{t('time_zone.priority')}/, :input_html => { :class => "input-xlarge" } %>
The trick here is using string interpolation inside a regular expression to provide the priority list.
DateTime Formats
config/locales/datetime.yml
en:
time:
# quote value so
brackets not interpreted as YAML list:
never_msg: '[never]'
format_labels:
mdyslash12: mm/dd/yyyy - hh:mm am (12-hour)
mdyslash24: mm/dd/yyyy - hh:mm (24-hour)
formats:
mdyslash12: ! '%m/%d/%Y %I:%M%p'
mdyslash24: ! '%m/%d/%Y %H:%M'
Here I’ve created two possible custom datetime formats and a “never_msg”.
app/views/_user_fields.html.erb
<%= f.input :datetime_format, :collection => t('time.format_labels'), :required => true, :value_method => :first, :label_method => :last, :input_html => { :class => "input-xlarge" } %>
Here the trick is that t('time.format_labels')
returns a hash of keys and values. And each element of that hash is returned as 2-item array. So for the select list values, we want the hash key, i.e. the :first
item in the array, and for the select list labels, we want the hash value, i.e. the :last
item in the array.
Another alternative would be to actually display the current time in localized form in the select list:
<%= f.input :datetime_format, :collection => t('time.format_labels'), :required => true, :label_method => lambda { |i| I18n.localize DateTime.now.in_time_zone (current_user.time_zone), :format => i.first }, :input_html => { :class => "input-xlarge" } %>
The :format
option of the I18n.localize
method tells it what format to use for displaying the date/time. (See guide.) :format
expects a symbol. Here we take advantage of the hash keys already being symbols, so we just retrieve they key with .first
). By the way, current_user
comes from the Devise authentication plugin.
Finally, to just display date/time values (as opposed to putting them in a select list in a form), I wrote a little helper:
app/helpers/application_helper.rb
# Localize a datetime value with a standard nil message # and a default format def l_dt(datetime, nilmsg = I18n.t('time.never_msg'), format = @datetime_format) datetime ? I18n.l(datetime, :format => format) : nilmsg end
Then to display a localized date/time, I just call that helper like this:
<%= l_dt @user.current_sign_in_at %>
I18n.localize
returns an error if you pass it a nil string. The l_dt
helper takes care of that by using a “never_msg” string, also retrieved (and optionally translated) from the locale file.