How do I format a date in ruby to include "rd" as in "3rd"
Asked Answered
S

8

26

I want to format a date object so that I can display strings such as "3rd July" or "1st October". I can't find an option in Date.strftime to generate the "rd" and "st". Any one know how to do this?

Shaven answered 4/7, 2009 at 10:12 Comment(0)
B
25

I'm going to echo everyone else, but I'll just encourage you to download the activesupport gem, so you can just use it as a library. You don't need all of Rails to use ordinalize.

% gem install activesupport
...
% irb 
irb> require 'rubygems'
#=>  true
irb> require 'activesupport'
#=>  true
irb> 3.ordinalize
#=>  "3rd"
Breakage answered 4/7, 2009 at 17:56 Comment(4)
Good point. You can also get this functionality from the facets (facets.rubyforge.org) library - require 'facets' or, for just this method, require 'facets/integer/ordinal'Abductor
How do we extract just the ordinalization? I want to do 3<span>th</span>Islander
Volte: 3.ordinalize.sub(/\w+/, '<span>\0</span>')Breakage
There's a much easier way to get what you want without manipulating the day integer by hand: date.to_s(:long_ordinal). See: api.rubyonrails.org/classes/Date.html#method-i-to_formatted_sMaculation
C
41

Unless you're using Rails, add this ordinalize method (code shamelessly lifted from the Rails source) to the Fixnum class

class Fixnum
  def ordinalize
    if (11..13).include?(self % 100)
      "#{self}th"
    else
      case self % 10
        when 1; "#{self}st"
        when 2; "#{self}nd"
        when 3; "#{self}rd"
        else    "#{self}th"
      end
    end
  end
end

Then format your date like this:

> now = Time.now
> puts now.strftime("#{now.day.ordinalize} of %B, %Y")
=> 4th of July, 2009
Collaborate answered 4/7, 2009 at 12:8 Comment(1)
Note that this answer is a bit outdated. Here's how it looks like now and here's the extension to the Integer class.Endodontics
Z
31
created_at.strftime("#{created_at.day.ordinalize} of %m, %y")

Will produce "4th of July, 2009"

Zollie answered 4/7, 2009 at 10:43 Comment(3)
I had to add a # in front of the { but this worked a treat Thanks!Hurlburt
how would you ordinalize the string variables? I need to turn %m for example.Trimmer
This is nice when you need to use the atypical "4th of July" format but there's no need to ordinalize by hand if you're using the conventional "July 4th, 2009": created_at.to_date.to_s(:long_ordinal).Maculation
B
25

I'm going to echo everyone else, but I'll just encourage you to download the activesupport gem, so you can just use it as a library. You don't need all of Rails to use ordinalize.

% gem install activesupport
...
% irb 
irb> require 'rubygems'
#=>  true
irb> require 'activesupport'
#=>  true
irb> 3.ordinalize
#=>  "3rd"
Breakage answered 4/7, 2009 at 17:56 Comment(4)
Good point. You can also get this functionality from the facets (facets.rubyforge.org) library - require 'facets' or, for just this method, require 'facets/integer/ordinal'Abductor
How do we extract just the ordinalization? I want to do 3<span>th</span>Islander
Volte: 3.ordinalize.sub(/\w+/, '<span>\0</span>')Breakage
There's a much easier way to get what you want without manipulating the day integer by hand: date.to_s(:long_ordinal). See: api.rubyonrails.org/classes/Date.html#method-i-to_formatted_sMaculation
D
8

I don't think Ruby has it, but if you have Rails, try this:-

puts 3.ordinalize #=> "3rd"
Deleterious answered 4/7, 2009 at 10:34 Comment(1)
It's also available in Facets.Thermostatics
S
1

Seems I'm revisiting this topic for a third time, so I've updated my gist with some extra comments / usage.

https://gist.github.com/alterisian/4154152

Cheers, Ian.

Spectrum answered 12/8, 2013 at 11:20 Comment(0)
S
1

I don't know if it makes it that much (any?) faster than switch-case, but I made a constant with the endings:

DAY_ENDINGS = ["th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "st"]

Then just used it like:

DAY_ENDINGS[date.mday]

As I wanted the ending inside a

<span>th</span>
Simsar answered 11/6, 2014 at 9:47 Comment(0)
C
1

require 'activesupport'
1.ordinal => 'st'
1.ordinalize => '1st'

Council answered 11/12, 2014 at 11:29 Comment(0)
S
0
require 'time'
H = Hash.new do |_,k|
  k +
  case k
  when '1', '21', '31'
    'st'
  when '2', '22'
    'nd'
  when '3', '23'
    'rd'
  else
    'th'
  end
end 
def fmt_it(time)
  time.strftime("%A %-d, %-l:%M%P").sub(/\d+(?=,)/, H) 
end
fmt_it(Time.new)
  #=> "Wednesday 9th, 1:36pm"
fmt_it(Time.new + 3*24*60*60)
  #=> "Saturday 12th, 3:15pm"

I have used the form of String#sub (one could use sub!) that takes a hash (H) as its second argument.

The regular expression used by sub reads "match one or more digits followed by a comma". (?=,) is a positive lookahead.

I created the (empty) hash H using the form of Hash::new that takes a block. This simply means that if H does not have a key k, H[k] returns the value computed by the block. In this case the hash is empty so the block always returns the value of interest. The block takes two arguments, the hash (here H) and the key being evaluated. I've represented the former with an underscore, signalling that it is not used by the block). Some examples:

H['1']  #=>  "1st" 
H['2']  #=>  "2nd" 
H['3']  #=>  "3rd" 
H['4']  #=>  "4th" 
H['9']  #=>  "9th" 
H['10'] #=> "10th" 
H['11'] #=> "11th" 
H['12'] #=> "12th" 
H['13'] #=> "13th" 
H['14'] #=> "14th" 
H['22'] #=> "22nd" 
H['24'] #=> "24th" 
H['31'] #=> "31st" 

See Time#strftime for formatting directives.

Swinger answered 10/9, 2020 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.