在Ruby on Rails中,如何格式化带有“ th”后缀的日期,例如“ Sun Oct 5th”?


177

我想以以下格式显示日期:周中的短日,短月,月中的日期,且不带前导零,但包括“ th”,“ st”,“ nd”或“ rd”后缀。

例如,询问该问题的那天将显示“ 10月2日星期四”。

我正在使用Ruby 1.8.7,而Time.strftime似乎没有执行此操作。我希望有一个标准库。


2
您可能想在问题或标题中使用“后缀”一词,以便其他人更容易找到。我不确定在谈论日期时是否还有这个词。
哈雷·霍尔科姆

很好的问题。我只是几天前才在想同样的事情-非常有帮助。
RichH

Answers:


278

使用'active_support'中的ordinalize方法。

>> time = Time.new
=> Fri Oct 03 01:24:48 +0100 2008
>> time.strftime("%a %b #{time.day.ordinalize}")
=> "Fri Oct 3rd"

注意,如果将IRB与Ruby 2.0一起使用,则必须首先运行:

require 'active_support/core_ext/integer/inflections'

15
请注意,这不在标准库中。
克里斯·劳埃德

97

您可以对数字使用active_support的序数化帮助器方法。

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

30

再接一点Patrick McKenzie的回答,您可以在config/initializers目录中创建一个名为date_format.rb(或任何您想要的文件)的新文件,并将其放入其中:

Time::DATE_FORMATS.merge!(
  my_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)

然后,在您的视图代码中,您只需将新的日期格式分配给它即可格式化任何日期:

My Date: <%= h some_date.to_s(:my_date) %>

它简单,有效且易于构建。只需在date_format.rb文件中为每种不同的日期格式添加更多格式行。这是一个更加充实的例子。

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

7
好答案。对于Rails 3,ActiveSupport进行了很大的更改,因此等效项如下:Time::DATE_FORMATS.merge!(:my_date => lambda { |time| time.strftime("%a, %b #{ActiveSupport::Inflector.ordinalize(time.day)}") })
Sidane


6

我喜欢Bartosz的回答,但是,嘿,既然这是我们正在谈论的Rails,那么就让它迈向弯曲吧。(编辑:尽管我只是简单地修补以下方法,但事实证明这是一种更干净的方法。)

DateTime实例具有to_formatted_sActiveSupport提供的方法,该方法将单个符号作为参数,并且,如果该符号被识别为有效的预定义格式,则返回具有适当格式的String。

这些符号由定义Time::DATE_FORMATS,这是标准格式功能...或procs的符号哈希。哇哈哈哈

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

但是,嘿,如果您无法忍受猴子补丁的机会,则可以始终提供一个更简洁的界面:

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

3

创建自己的%o格式。

初始化器

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 }

用法

Time.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"

您还可以将其与Date和一起使用DateTime

DateTime.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"

Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"

不知道这是否记录在案。我似乎找不到任何记录,但是我们在代码库中使用了它,因此必须在某处找到它。
约书亚·品特

1
我无法在2.6.3上使用它。也许是在旧版本的Ruby中?还是有人Time在您的项目中修补了猴子?
kcdragon

2
@kcdragon哇,你说的很对。搜索代码库,发现我的老兄Chuck Bergeron在将近7年前添加了此初始化程序。无论如何,我仍然觉得这非常有用,因此我已经更新了答案,如我们在CNTRAL中所实现的那样。
约书亚·品特(

2

尽管乔纳森·特兰(Jonathan Tran)确实说过他首先要寻找星期几的缩写,然后才是缩写的月份,但我认为对于那些最终了解Rails的开箱即用支持的人来说,这可能是有用的。通常可用的长月,有序的日期整数,后跟年份,如中所示June 1st, 2018

使用以下方法可以轻松实现:

Time.current.to_date.to_s(:long_ordinal)
=> "January 26th, 2019"

要么:

Date.current.to_s(:long_ordinal)
=> "January 26th, 2019"

如果您愿意,也可以坚持一个时间实例:

Time.current.to_s(:long_ordinal)
=> "January 26th, 2019 04:21"

您可以在Rails API文档中找到有关如何创建自定义样式的更多格式和上下文。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.