Rails - using capitalize on a month name from l18n - ruby-on-rails

I have a string like this in my view
<%= l event.start_date, format: :long %>
which outputs
18 aout 2013
I would like to capitalize the month name without touching the yaml file, and tried several options which failed miserably. Is it possible?

If you call capitalize it only takes the first character, so you may use titleize
<%=(l Date.today, format: :long) %>
=> "Miércoles, 28 de agosto de 2013"
<%=(l Date.today, format: :long).titleize %>
=> "Miércoles, 28 De Agosto De 2013"
Please note that all the words are turned to capital letter
Update
$ rails c
Loading development environment (Rails 4.0.0)
>> helper.l Date.today, format: :long
=> "September 02, 2013"
>> helper.l Time.now, format: :long
=> "September 02, 2013 22:56"

Related

How do I format my created_at output correctly with I18n?

I am using this I18n file.
I am calling it in my view like this:
<td class="center"><%= l o.created_at %></td>
This is being outputted like this:
Mon, 22 May 2013 04:04:43 +0000
For starters, why is it displaying May 22, 2013 and not April 22?
When I do it in the console, I get this:
> o.created_at
=> Mon, 22 Apr 2013 04:04:43 UTC +00:00
I don't want it to display the time, or rather would prefer to just say something like:
Monday, April 22, 2013 # 4:04am
How do I do that?
You can add custom date/time formats to your translation file. To see what time-based substitutions are possible, consult a reference for strfime
formats:
default: ! '%Y-%m-%d'
long: ! '%B %d, %Y'
short: ! '%b %d'
custom: ! '%A, %M %B, %Y # %l:%M%P'
In your view, you'd make use as follows:
<%= l o.created_at, :format => :custom %>
You may need to get rid of blank entries in your en.yml file to correct your translation errors.

Localize a whole sentense passing it a datetime

I googled around but didn't find an answer - even if I guess it isn't tricky!
I'd like to localize a sentense that icludes date and time parameter. I want to pass it a complete datetime.
de_txt.yml
de:
article:
will_be_published_at: 'Wartet auf Veröffentlichung am %a %e. %b %Y um %H:%M Uhr'
My function with d is out of the database, field type is datetime
(second line is the one of my problem)
def icon_article_will_be_published_at(d)
alt = t('article.will_be_published_at', d)
image_tag("#{root_url}images/famfamfam/icons/date_next.png", :title => alt, :alt => alt, :class => "icon")
end
more about d
d.inspect # => Sat, 03 Dec 2011 14:07:00 CET +01:00
I can't figure it out and would appreciate help.
For this, you will need the I18n#l method, not the translate method.
It's a bit tricky, because you need a separate time format in the translations file (de.yml). This is one way to do it (adjust as necessary):
In config/locales/de.yml:
de:
time:
formats:
article_published_at: 'Wartet auf Veröffentlichung am %a %e. %b %Y um %H:%M Uhr'
Testing it in the console:
I18n.locale = :de
I18n.l Time.now, :format => :article_published_at
I would propose the following:
Split what you want to do in 2 steps:
Define a special format :um as described in the Rails Guide to I18n
de:
article:
will_be_published_at: 'Wartet auf Veröffentlichung am %datetime'
time:
formats:
um: "%a %e. %b %Y um %H:%M Uhr"
Call it then in the following snippet:
time = l(d, :format => :um)
alt = t('article.will_be_published_at', :datetime => time)
I could not test it, but it should work.

Extra space in cucumber step when using to_s(:long)

I have a step that fails with the following...
expected #has_content?("July 4, 2009") to return true, got false
The problem, I think, is the extra space between "July" and "4". I am using published_on.to_s(:long) in both the step definition and the view, so I'm not entirely sure where the extra space is coming from.
Any ideas?
It's what happens when you try:
Date.civil(2010, 7, 4).strftime("%e") # => " 4"
And Rails uses %e in their :long format. The funny thing is that %e isn't documented.
I would adjust my step definition to match Ruby behavior if you don't care about the extra space (extra spaces won't show in HTML anyway). If you do care about it, squish it:
Date.civil(2010, 7, 4).to_s(:long).squish # => "July 4, 2010"
Squish is avaiable in Rails 3. If you're using Rails 2, you can use gsub:
Date.civil(2010, 7, 4).to_s(:long).gsub(/\s+/, " ") # => "July 4, 2010"
I ran into the same problem with my cucumber test today!
The problem (as iain pointed out) is that Date::DATE_FORMATS[:long] is "%B %e, %Y". The %e, according to ri strftime, yields a blank-padded day number:
%d - Day of the month, zero-padded (01..31)
%-d no-padded (1..31)
%e - Day of the month, blank-padded ( 1..31)
So by default, this is what I see in Rails 3.1.3:
> d = '2012-02-01'.to_date
=> Wed, 01 Feb 2012
> d.to_s(:long)
=> "February 1, 2012"
Strangely, Rails uses a different day format for the :long format of times (%d, which yields "01") as for dates (%e, which yields " 1"):
> d = '2012-02-01'.to_time
=> 2012-02-01 00:00:00 UTC
> d.to_s(:long)
=> "February 01, 2012 00:00"
> Time::DATE_FORMATS[:long]
=> "%B %d, %Y %H:%M"
> Date::DATE_FORMATS[:long]
=> "%B %e, %Y"
The solution then is to use "%-d" for the day in your format string instead of %e:
> Date::DATE_FORMATS[:long] = "%B %-d, %Y"
=> "%B %-d, %Y"
> d = '2012-02-01'.to_date
Wed, 01 Feb 2012
> d.to_s(:long)
=> "February 1, 2012"
You can just add this line to a new initializer, config/initializers/date_formats.rb:
Date::DATE_FORMATS[:long] = "%B %-d, %Y"
Please comment on https://github.com/rails/rails/pull/1994 if you would like to see this default changed in Rails.
For what it's worth, I would rather use the "%-d" fix (or even "%-e"! which gives the same results) than ".squish", which is Rails-specific, and not as portable (why not use the Ruby-native ".squeeze", or even ".squeeze(' ')" at that then, if you don't want to mess around with the date formats?).
Also, as an update: #iain mentions that '%e' isn't documented. For what it's worth, it is now! (although interestingly, not "%-e" specifically, which, if you do try it, is valid, and works!)

Timestamps look different

In Rails, I find that timestamps in the console look different to the actual html view even when you have the same code. Unless I'm doing something really stupid:
>> article = News.first
=> #<News id: 1, title: "Testing", body: "yadda yadda", role_id: 1, created_at: "2009-04-12 05:33:07", updated_at: "2009-04-12 05:33:07">
>> article.created_at
=> Sun, 12 Apr 2009 05:33:07 UTC +00:00
>> article.created_at.to_date
=> Sun, 12 Apr 2009
And in the view:
<% for article in #news %>
<% #current_date = article.created_at.to_date %>
<% if #current_date != #date %>
<%= #current_date %>
<% #date = #current_date %>
<% end %>
The output will be:
2009-04-14
Why are the formats different?
In config/initializers/time_formats.rb, write:
Time::DATE_FORMATS[:article] = "%a, %d %B %Y"
<%= calls to_s on the Date object, which results in 2009-04-14 no matter where it's called:
>> Date.today
=> Tue, 14 Apr 2009
>> Date.today.to_s
=> "2009-04-14"
I really don't know what gets called when you don't use to_s.
UPDATE: Now I know. If you don't use to_s or an equivalent, irb calls inspect on the date object:
>> Date.today.inspect
=> "Tue, 14 Apr 2009"
UPDATE 2:
You can replace #current_date with #current_date.to_s (or #current_date.to_s(:format)) in your view. Format can be short, long, db, long_ordinal, rfc822 or number.
You can also define a default date format in your application locale.

In Ruby on Rails, how do I format a date with the "th" suffix, as in, "Sun Oct 5th"?

I want to display dates in the format: short day of week, short month, day of month without leading zero but including "th", "st", "nd", or "rd" suffix.
For example, the day this question was asked would display "Thu Oct 2nd".
I'm using Ruby 1.8.7, and Time.strftime just doesn't seem to do this. I'd prefer a standard library if one exists.
Use the ordinalize method from 'active_support'.
>> time = Time.new
=> Fri Oct 03 01:24:48 +0100 2008
>> time.strftime("%a %b #{time.day.ordinalize}")
=> "Fri Oct 3rd"
Note, if you are using IRB with Ruby 2.0, you must first run:
require 'active_support/core_ext/integer/inflections'
You can use active_support's ordinalize helper method on numbers.
>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"
Taking Patrick McKenzie's answer just a bit further, you could create a new file in your config/initializers directory called date_format.rb (or whatever you want) and put this in it:
Time::DATE_FORMATS.merge!(
my_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
Then in your view code you can format any date simply by assigning it your new date format:
My Date: <%= h some_date.to_s(:my_date) %>
It's simple, it works, and is easy to build on. Just add more format lines in the date_format.rb file for each of your different date formats. Here is a more fleshed out example.
Time::DATE_FORMATS.merge!(
datetime_military: '%Y-%m-%d %H:%M',
datetime: '%Y-%m-%d %I:%M%P',
time: '%I:%M%P',
time_military: '%H:%M%P',
datetime_short: '%m/%d %I:%M',
due_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
>> require 'activesupport'
=> []
>> t = Time.now
=> Thu Oct 02 17:28:37 -0700 2008
>> formatted = "#{t.strftime("%a %b")} #{t.day.ordinalize}"
=> "Thu Oct 2nd"
Although Jonathan Tran did say he was looking for the abbreviated day of the week first followed by the abbreviated month, I think it might be useful for people who end up here to know that Rails has out-of-the-box support for the more commonly usable long month, ordinalized day integer, followed by the year, as in June 1st, 2018.
It can be easily achieved with:
Time.current.to_date.to_s(:long_ordinal)
=> "January 26th, 2019"
Or:
Date.current.to_s(:long_ordinal)
=> "January 26th, 2019"
You can stick to a time instance if you wish as well:
Time.current.to_s(:long_ordinal)
=> "January 26th, 2019 04:21"
You can find more formats and context on how to create a custom one in the Rails API docs.
Create your own %o format.
Initializer
config/initializers/srtftime.rb
module StrftimeOrdinal
def self.included( base )
base.class_eval do
alias_method :old_strftime, :strftime
def strftime( format )
old_strftime format.gsub( "%o", day.ordinalize )
end
end
end
end
[ Time, Date, DateTime ].each{ |c| c.send :include, StrftimeOrdinal }
Usage
Time.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
You can use this with Date and DateTime as well:
DateTime.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
I like Bartosz's answer, but hey, since this is Rails we're talking about, let's take it one step up in devious. (Edit: Although I was going to just monkeypatch the following method, turns out there is a cleaner way.)
DateTime instances have a to_formatted_s method supplied by ActiveSupport, which takes a single symbol as a parameter and, if that symbol is recognized as a valid predefined format, returns a String with the appropriate formatting.
Those symbols are defined by Time::DATE_FORMATS, which is a hash of symbols to either strings for the standard formatting function... or procs. Bwahaha.
d = DateTime.now #Examples were executed on October 3rd 2008
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
d.to_formatted_s :weekday_month_ordinal #Fri Oct 3rd
But hey, if you can't resist the opportunity to monkeypatch, you could always give that a cleaner interface:
class DateTime
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
def to_my_special_s
to_formatted_s :weekday_month_ordinal
end
end
DateTime.now.to_my_special_s #Fri Oct 3rd

Resources