how do I get name of the month in ruby on Rails?
Ref this
<% @date = Date.today %>
<%= @date.strftime("%B")%>
if
@date >> Fri, 11 Jun 2010
then
@date.strftime("%B") >> "June"
How can I get month name from month number
Use format string.
(Time.now + 1.month).strftime("%B")
# => "October"
Name of this month (Date.today.month as name)
Date::MONTHNAMES[Date.today.month]
would give you "January". (You may need to require 'date'
first).
Extract month name from string in Ruby
Date::MONTHNAMES
may be able to help you. If they are always 3-character shortened versions of the months, you could build a hash to help:
dates = Date::MONTHNAMES.compact.map { |m| [m[0..2], m] }.to_h
Then use it elsewhere:
text = 'Up 4.35% from Oct to Nov'
text.gsub(/#{dates.keys.join('|')}/, dates)
=> "Up 4.35% from October to November"
Get last X month names in Rails
A slightly uglier version that builds on Olives' answer, but doesn't require looking up dates in each month and is about 31x faster:
current_month = Date.today.month
month_names = 6.downto(1).map { |n| DateTime::MONTHNAMES.drop(1)[(current_month - n) % 12] }
Output when current_month
is 4 (to test Dec-Jan rollover):
["November", "December", "January", "February", "March", "April"]
Benchmark:
Benchmark.measure do
10000.times do
current_month = Date.today.month
month_names = 6.downto(1).map { |n| DateTime::MONTHNAMES.drop(1)[(current_month - n) % 12] }
end
end
=> #<Benchmark::Tms:0x007fcfda4830d0 @label="", @real=0.12975036300485954, @cstime=0.0, @cutime=0.0, @stime=0.07000000000000006, @utime=0.06999999999999984, @total=0.1399999999999999>
Compare to the cleaner version:
Benchmark.measure do
10000.times do
5.downto(0).collect do |n|
Date::MONTHNAMES[n.months.ago.month]
end
end
end
=> #<Benchmark::Tms:0x007fcfdcbde9b8 @label="", @real=3.7730263769917656, @cstime=0.0, @cutime=0.0, @stime=0.04999999999999993, @utime=3.69, @total=3.7399999999999998>
Print month names into the view in Rails
You can get month names in
Date::ABBR_MONTHNAMES.dup.slice(1,12)
assign them in array and loop through
EDIT
controller
months = Date::ABBR_MONTHNAMES.dup.slice(1,12)
view
<ul class="nav nav-tabs">
<% months.each do |month| %>
<li><a href="#"><%= month %></a></li>
<% end %>
</ul>
Get month names between two dates
I'd go with:
d1 = Date.parse('jan 1 2011')
d2 = Date.parse('dec 31 2012')
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ Date.strptime(m, '%Y%m').mon ] }
=> ["Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"]
or:
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\d\d$/ ].to_i ] }
which is probably a little faster.
The problem is the year boundary. You have to track years and months, not just the months, otherwise you'll remove all the duplicated month indexes when using uniq
to remove the days. I went with the YYYYMM
format, to get the right granularity.
require 'benchmark'
require 'date'
d1 = Date.parse('jan 1 2011')
d2 = Date.parse('dec 31 2012')
n = 100
Benchmark.bm(8) do |x|
x.report('strptime') { n.times { (d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ Date.strptime(m, '%Y%m').mon ] } } }
x.report('regex') { n.times { (d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\\d\\d$/ ].to_i ] } } }
end
user system total real
strptime 3.060000 0.020000 3.080000 ( 3.076614)
regex 2.820000 0.010000 2.830000 ( 2.829366)
EDIT:
Let's make it even more interesting.
I had some code smell that kept bugging me. I didn't like using Date.strftime
and Date.strptime
, so I took another run at the problem: Here are two more solutions that are running a lot faster, along with the benchmarks:
require 'benchmark'
require 'date'
def regex_months_between(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
(d1..d2).map{ |m| m.strftime('%Y%m') }.uniq.map{ |m| Date::ABBR_MONTHNAMES[ m[/\d\d$/ ].to_i ] }
end
def months_between1(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
months = (d2.mon - d1.mon) + (d2.year - d1.year) * 12
month_names = []
months.times{ |m|
month_names << Date::ABBR_MONTHNAMES[(d1 >> m).mon]
}
month_names << Date::ABBR_MONTHNAMES[d2.mon]
month_names
end
def months_between2(d1, d2)
d1, d2 = [d1, d2].map{ |d| Date.parse(d) }.minmax
months = (d2.mon - d1.mon) + (d2.year - d1.year) * 12
(d1.mon ... (d1.mon + months)).each_with_object(Date::ABBR_MONTHNAMES[d1.mon, 1]) { |month_offset, month_names_array|
month_names_array << Date::ABBR_MONTHNAMES[(d1 >> month_offset).mon]
}
end
puts regex_months_between('jan 1 2011', 'dec 31 2012').join(', ')
puts months_between1('jan 1 2011', 'dec 31 2012').join(', ')
puts months_between2('jan 1 2011', 'dec 31 2012').join(', ')
n = 100
Benchmark.bm(3) do |b|
b.report('rmb') { n.times { regex_months_between('jan 1 2011', 'dec 31 2012') } }
b.report('mb1') { n.times { months_between1('jan 1 2011', 'dec 31 2012') } }
b.report('mb2') { n.times { months_between2('jan 1 2011', 'dec 31 2012') } }
end
With output looking like:
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
user system total real
rmb 2.810000 0.010000 2.820000 ( 2.820732)
mb1 0.060000 0.000000 0.060000 ( 0.057763)
mb2 0.060000 0.000000 0.060000 ( 0.057112)
Interesting. "rmb
" is now running way behind. Pulling it from the tests and bumping up the loops 100x:
n = 10_000
Benchmark.bm(3) do |b|
b.report('mb1') { n.times { months_between1('jan 1 2011', 'dec 31 2012') } }
b.report('mb2') { n.times { months_between2('jan 1 2011', 'dec 31 2012') } }
end
Which gives:
user system total real
mb1 5.570000 0.060000 5.630000 ( 5.615789)
mb2 5.570000 0.040000 5.610000 ( 5.611323)
It's basically a tie between the two new ways of getting the months. Being anal, I'd go with mb2
because it'd be a little bit faster if I was doing this millions of times, but your mileage might vary.
Find month names for the last year
In Rails you can do something like this:
<% 11.downto(0) do |i| %>
<%= i.months.ago.strftime("%B %Y") %>
<% end %>
Localize month names - Calendar Railscasts #213
You should use the localize
method of I18n (shortened as l
):
<h2 id="month"><%= l(@date) %></h2>
Then you can set different formats on your own:
http://guides.rubyonrails.org/i18n.html#adding-date-time-formats
# config/locales/es.yml
es:
date:
formats:
short: "%B %Y"
default: "%D %m, %Y"
And use it like this:
<h2 id="month"><%= l(@date, format: :short) %></h2>
Related Topics
Why Is "❨╯°□°❩╯︵┻━┻" with Such an Encoding Used for a Method Name
How to Embed Ruby in JavaScript (Rails + .Html.Erb File)
Bundle Command Not Found Windows X64
Gem Install Mongrel Fails with Ruby 1.9.1
Retrieving Image Height with Carrierwave
Ruby Amazon S3 Access Denied When Listing Buckets
Ruby - Create Singleton with Parameters
Running Parallel Selenium Tests with Capybara
Rails Return JSON Serialized Attribute With_Indifferent_Access
Ruby: How to Calculate a Path Relative to Another One
Warning: String Literal in Condition
How to Escape a Single Quote in Ruby
Ruby - Array.Join Versus String Concatenation (Efficiency)
How to Run a Simple Ruby Script in Any Web Server (Apache or Mongrel or Any Thing Else)