In Ruby on Rails, come posso formattare una data con il suffisso "th", come in "Sun 5 ottobre"?


177

Voglio visualizzare le date nel formato: giorno corto della settimana, mese corto, giorno del mese senza zero iniziale ma includendo il suffisso "th", "st", "nd" o "rd".

Ad esempio, il giorno in cui è stata posta questa domanda verrà visualizzato "Gio 2 ottobre".

Sto usando Ruby 1.8.7 e Time.strftime proprio non sembra farlo. Preferirei una libreria standard se ne esiste una.


2
Potresti voler usare la parola "suffisso" nella tua domanda o titolo per rendere questo più facile da trovare per altre persone. Non sono sicuro che ci sia un'altra parola per questo quando si parla di date.
Harley Holcombe,

Ottima domanda Stavo pensando la stessa cosa solo un paio di giorni fa - molto utile.
RichH

Risposte:


278

Utilizzare il metodo ordinalize da 'active_support'.

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

Nota, se stai usando IRB con Ruby 2.0, devi prima eseguire:

require 'active_support/core_ext/integer/inflections'

15
Basta notare che questo non è nella libreria standard.
Chris Lloyd,

97

È possibile utilizzare il metodo helper ordinalize di active_support sui numeri.

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

30

Prendendo la risposta di Patrick McKenzie ancora un po ', potresti creare un nuovo file nella tua config/initializersdirectory chiamato date_format.rb(o come vuoi) e inserirlo in questo:

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

Quindi nel tuo codice di visualizzazione puoi formattare qualsiasi data semplicemente assegnandole il tuo nuovo formato data:

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

È semplice, funziona ed è facile da costruire. Aggiungi solo più righe di formato nel file date_format.rb per ciascuno dei tuoi diversi formati di data. Ecco un esempio più elaborato.

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
Bella risposta. Per Rails 3, ActiveSupport è cambiato parecchio, quindi l'equivalente è il seguente: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

Mi piace la risposta di Bartosz, ma ehi, dato che si tratta di Rails di cui stiamo parlando, facciamo un passo avanti in modo subdolo. (Modifica: anche se stavo per eseguire il monkeypatch con il seguente metodo, risulta che esiste un modo più pulito.)

DateTimele istanze hanno un to_formatted_smetodo fornito da ActiveSupport, che accetta un singolo simbolo come parametro e, se quel simbolo è riconosciuto come un formato predefinito valido, restituisce una stringa con la formattazione appropriata.

Questi simboli sono definiti da Time::DATE_FORMATS, che è un hash di simboli per entrambe le stringhe per la funzione di formattazione standard ... o 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

Ma hey, se non riesci a resistere all'opportunità di monkeypatch, potresti sempre dare un'interfaccia più pulita:

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

Crea il tuo %oformato.

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 }

uso

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

Puoi usarlo con Datee DateTimeanche:

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

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

Non sono sicuro se questo è documentato. Non riesco a trovarne alcun record ma lo stiamo usando nella nostra base di codice, quindi devo averlo trovato da qualche parte.
Joshua Pinter,

1
Non riesco a farlo funzionare su 2.6.3. Forse era in una versione precedente di Ruby? O forse qualcuno scimmia rattoppato Timenel tuo progetto?
kcdragon,

2
@kcdragon Wow, avevi assolutamente ragione. Ho cercato la base di codice e ho scoperto che il mio vecchio amico Chuck Bergeron ha aggiunto questo inizializzatore circa 7 anni fa. Indipendentemente da ciò, lo trovo ancora molto utile, quindi ho aggiornato la risposta su come implementarlo come ce l'abbiamo in CNTRAL.
Joshua Pinter,

2

Anche se Jonathan Tran ha detto che stava cercando il giorno abbreviato della settimana seguito per primo dal mese abbreviato, penso che potrebbe essere utile per le persone che finiscono qui per sapere che Rails ha un supporto immediato per il più mese lungo comunemente utilizzabile, numero intero giorno ordinalizzato, seguito dall'anno, come in June 1st, 2018.

Può essere facilmente raggiunto con:

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

O:

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

Se lo desideri, puoi attenersi a un'istanza temporale:

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

Puoi trovare più formati e contesto su come crearne uno personalizzato nei documenti dell'API di Rails .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.