Trong Ruby on Rails, làm cách nào để định dạng một ngày với hậu tố của điều đó, như trong, Sun Sun ngày 5 tháng 10?


177

Tôi muốn hiển thị ngày theo định dạng: ngày ngắn trong tuần, tháng ngắn, ngày trong tháng mà không dẫn đầu số 0 nhưng bao gồm hậu tố "th", "st", "nd" hoặc "nd".

Ví dụ: ngày câu hỏi này được hỏi sẽ hiển thị "Ngày 2 tháng 10".

Tôi đang sử dụng Ruby 1.8.7 và Time.strftime dường như không làm điều này. Tôi muốn một thư viện tiêu chuẩn nếu có.


2
Bạn có thể muốn sử dụng từ "hậu tố" trong câu hỏi hoặc tiêu đề của mình để làm cho điều này dễ tìm hơn đối với người khác. Tôi không chắc có một từ khác cho điều này khi nói về ngày.
Harley Holcombe

Câu hỏi tuyệt vời. Tôi đã suy nghĩ điều tương tự chỉ một vài ngày trước - rất hữu ích.
RichH

Câu trả lời:


278

Sử dụng phương pháp thứ tự từ 'active_support'.

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

Lưu ý, nếu bạn đang sử dụng IRB với Ruby 2.0, trước tiên bạn phải chạy:

require 'active_support/core_ext/integer/inflections'

15
Chỉ cần lưu ý điều này không có trong thư viện tiêu chuẩn.
Chris Lloyd

97

Bạn có thể sử dụng phương thức trợ giúp thông thường của active_support trên các số.

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

30

Lấy câu trả lời của Patrick McKenzie thêm một chút nữa, bạn có thể tạo một tệp mới trong config/initializersthư mục của bạn được gọi date_format.rb(hoặc bất cứ điều gì bạn muốn) và đặt nó vào đó:

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

Sau đó, trong mã xem của bạn, bạn có thể định dạng bất kỳ ngày nào chỉ bằng cách gán cho nó định dạng ngày mới của bạn:

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

Nó đơn giản, nó hoạt động và dễ dàng để xây dựng. Chỉ cần thêm nhiều dòng định dạng trong tệp date_format.rb cho mỗi định dạng ngày khác nhau của bạn. Đây là một ví dụ xác thịt hơn.

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
Câu trả lời tốt đẹp. Đối với Rails 3, ActiveSupport đã thay đổi khá nhiều, do đó, sau đây là tương đương:Time::DATE_FORMATS.merge!(:my_date => lambda { |time| time.strftime("%a, %b #{ActiveSupport::Inflector.ordinalize(time.day)}") })
Sidane

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

6

Tôi thích câu trả lời của Bartosz, nhưng này, vì đây là Rails mà chúng ta đang nói đến, chúng ta hãy tiến lên một bước trong tà đạo. (Chỉnh sửa: Mặc dù tôi sẽ chỉ sử dụng phương pháp sau đây, nhưng hóa ra có một cách sạch hơn.)

DateTimecác phiên bản có một to_formatted_sphương thức được cung cấp bởi ActiveSupport, lấy một ký hiệu làm tham số và, nếu biểu tượng đó được nhận dạng là định dạng được xác định trước hợp lệ, sẽ trả về một Chuỗi có định dạng phù hợp.

Các ký hiệu đó được xác định bởi Time::DATE_FORMATS, đó là hàm băm của các ký hiệu cho một chuỗi cho hàm định dạng chuẩn ... hoặc 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

Nhưng này, nếu bạn không thể cưỡng lại cơ hội để bắt khỉ, bạn luôn có thể cung cấp cho giao diện sạch hơn:

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

Tạo %ođịnh dạng của riêng bạn .

Công cụ khởi tạ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 }

Sử dụng

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

Bạn có thể sử dụng cái này với DateDateTimecả:

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

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

Không chắc chắn nếu điều này được ghi lại. Tôi dường như không thể tìm thấy bất kỳ bản ghi nào về nó nhưng chúng tôi đang sử dụng nó trong cơ sở mã của chúng tôi vì vậy phải tìm thấy nó ở đâu đó.
Joshua Pinter

1
Tôi không thể làm điều này để làm việc trên 2.6.3. Có lẽ đó là phiên bản cũ của Ruby? Hoặc có thể một con khỉ vá Timetrong dự án của bạn?
kcdragon

2
@kcdragon Wow, bạn đã hoàn toàn đúng. Tìm kiếm codebase và thấy rằng bạn thân cũ của tôi Chuck Bergeron đã thêm trình khởi tạo này gần 7 năm trước. Bất kể, tôi vẫn thấy điều này rất hữu ích vì vậy tôi đã cập nhật câu trả lời với cách triển khai giống như chúng tôi có trong CNTRAL.
Joshua Pinter

2

Mặc dù Jonathan Tran đã nói rằng anh ta đang tìm kiếm ngày viết tắt của tuần đầu tiên sau tháng viết tắt, tôi nghĩ rằng nó có thể hữu ích cho những người cuối cùng ở đây để biết rằng Rails có hỗ trợ ngoài luồng cho nhiều hơn thường có thể sử dụng tháng dài, số nguyên ngày thứ tự, tiếp theo là năm, như trong June 1st, 2018.

Nó có thể dễ dàng đạt được với:

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

Hoặc là:

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

Bạn có thể bám vào một ví dụ thời gian nếu bạn muốn:

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

Bạn có thể tìm thấy nhiều định dạng và ngữ cảnh hơn về cách tạo một tùy chỉnh trong tài liệu API Rails .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.