Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

How do I change the date format in Ruby on Rails?

You need to convert your string into Date object. For that, use Date#strptime . You can use Date#strftime to convert the Date object into preferred format.


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"

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

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"