Di Ruby on Rails, bagaimana cara memformat tanggal dengan akhiran "th", seperti pada, "Sun 5 Oktober"?

177

Saya ingin menampilkan tanggal dalam format: hari pendek dalam seminggu, bulan pendek, hari dalam sebulan tanpa memimpin nol tetapi termasuk akhiran "th", "st", "nd", atau "rd".

Misalnya, hari pertanyaan ini ditanyakan akan menampilkan "Kamis 2 Oktober".

Saya menggunakan Ruby 1.8.7, dan Time.strftime sepertinya tidak melakukan ini. Saya lebih suka perpustakaan standar jika ada.

Jonathan Tran
sumber
2
Anda mungkin ingin menggunakan kata "suffix" dalam pertanyaan atau judul Anda untuk mempermudah pencarian orang lain. Saya tidak yakin apakah ada kata lain untuk ini ketika berbicara tentang kencan.
Harley Holcombe
Pertanyaan yang sangat bagus Saya memikirkan hal yang sama hanya beberapa hari yang lalu - sangat membantu.
RichH

Jawaban:

278

Gunakan metode ordinalize dari 'active_support'.

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

Catatan, jika Anda menggunakan IRB dengan Ruby 2.0, Anda harus terlebih dahulu menjalankan:

require 'active_support/core_ext/integer/inflections'
Bartosz Blimke
sumber
15
Perhatikan saja ini tidak ada di perpustakaan standar.
Chris Lloyd
97

Anda dapat menggunakan metode helper bantu ordinalalize active_support pada angka.

>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"
mwilliams
sumber
30

Mengambil jawaban Patrick McKenzie sedikit lebih jauh, Anda dapat membuat file baru di config/initializersdirektori Anda yang disebut date_format.rb(atau apa pun yang Anda inginkan) dan memasukkan ini ke dalamnya:

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

Kemudian dalam kode tampilan Anda, Anda dapat memformat tanggal apa pun hanya dengan menetapkannya sebagai format tanggal baru:

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

Sederhana, ini bekerja, dan mudah untuk dikembangkan. Cukup tambahkan lebih banyak baris format dalam file date_format.rb untuk masing-masing format tanggal yang berbeda. Ini adalah contoh yang lebih sempurna.

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}") }
)
Richard Hurt
sumber
7
Jawaban bagus. Untuk Rails 3, ActiveSupport telah berubah sedikit, jadi yang berikut ini adalah yang setara: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"
Jimmy Schementi
sumber
6

Saya suka jawaban Bartosz, tapi hei, karena ini Rails yang sedang kita bicarakan, mari kita selangkah lebih maju dengan licik. (Sunting: Meskipun saya hanya akan monkeypatch metode berikut, ternyata ada cara yang lebih bersih.)

DateTimeinstance memiliki to_formatted_smetode yang disediakan oleh ActiveSupport, yang menggunakan simbol tunggal sebagai parameter dan, jika simbol itu dikenali sebagai format standar yang valid, mengembalikan sebuah String dengan pemformatan yang sesuai.

Simbol-simbol tersebut didefinisikan oleh Time::DATE_FORMATS, yang merupakan hash simbol untuk string baik untuk fungsi format standar ... atau 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

Tapi hei, jika Anda tidak bisa menolak kesempatan untuk melakukan monkeypatch, Anda selalu bisa memberikan antarmuka yang lebih bersih:

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
Patrick McKenzie
sumber
3

Buat %oformat Anda sendiri .

Inisialisasi

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 }

Pemakaian

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

Anda dapat menggunakan ini dengan Datedan DateTimejuga:

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

Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
Joshua Pinter
sumber
Tidak yakin apakah ini didokumentasikan. Sepertinya saya tidak dapat menemukan catatan apa pun tetapi kami menggunakannya di basis kode kami sehingga harus menemukannya di suatu tempat.
Joshua Pinter
1
Saya tidak bisa menjalankan ini pada 2.6.3. Mungkin itu dalam versi Ruby yang lebih lama? Atau mungkin seseorang monyet ditambal Timedalam proyek Anda?
kcdragon
2
@kcdragon Wow, Anda memang benar. Mencari basis kode dan menemukan bahwa teman lama saya Chuck Bergeron menambahkan inisialisasi ini hampir 7 tahun yang lalu. Apapun, saya masih menemukan ini sangat berguna jadi saya sudah memperbarui jawabannya dengan cara mengimplementasikannya seperti yang kita miliki di CNTRAL.
Joshua Pinter
2

Meskipun Jonathan Tran memang mengatakan dia mencari hari yang disingkat dalam minggu pertama diikuti oleh bulan yang disingkat, saya pikir mungkin berguna bagi orang-orang yang berakhir di sini untuk mengetahui bahwa Rails memiliki dukungan out-of-the-box untuk lebih biasanya bulan panjang yang dapat digunakan, bilangan bulat hari ordinalized, diikuti oleh tahun, seperti pada June 1st, 2018.

Itu dapat dengan mudah dicapai dengan:

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

Atau:

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

Anda dapat tetap menggunakan contoh waktu jika ingin juga:

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

Anda dapat menemukan lebih banyak format dan konteks tentang cara membuat custom di Rails API docs .

Olivier Lacan
sumber