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

Ruby on-RailsRubyDate

Ruby on-Rails Problem Overview


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.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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'

Solution 2 - Ruby on-Rails

You can use active_support's ordinalize helper method on numbers.

>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"

Solution 3 - Ruby on-Rails

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}") }
)

Solution 4 - Ruby on-Rails

>> require 'activesupport'
=> []
>> t = Time.now
=> Thu Oct 02 17:28:37 -0700 2008
>> formatted = "#{t.strftime("%a %b")} #{t.day.ordinalize}"
=> "Thu Oct 2nd"

Solution 5 - Ruby on-Rails

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

Solution 6 - Ruby on-Rails

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"

Solution 7 - Ruby on-Rails

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJonathan TranView Question on Stackoverflow
Solution 1 - Ruby on-RailsBartosz BlimkeView Answer on Stackoverflow
Solution 2 - Ruby on-RailsmwilliamsView Answer on Stackoverflow
Solution 3 - Ruby on-RailsRichard HurtView Answer on Stackoverflow
Solution 4 - Ruby on-RailsJimmy SchementiView Answer on Stackoverflow
Solution 5 - Ruby on-RailsPatrick McKenzieView Answer on Stackoverflow
Solution 6 - Ruby on-RailsJoshua PinterView Answer on Stackoverflow
Solution 7 - Ruby on-RailsOlivier LacanView Answer on Stackoverflow