Wie formatiere ich in Ruby on Rails ein Datum mit dem Suffix "th" wie in "Sun Oct 5th"?

177

Ich möchte Datumsangaben im folgenden Format anzeigen: kurzer Wochentag, kurzer Monat, Tag des Monats ohne führende Null, jedoch mit dem Suffix "th", "st", "nd" oder "rd".

An dem Tag, an dem diese Frage gestellt wurde, wird beispielsweise "Do 2. Oktober" angezeigt.

Ich verwende Ruby 1.8.7 und Time.strftime scheint dies einfach nicht zu tun. Ich würde eine Standardbibliothek bevorzugen, falls eine existiert.

Jonathan Tran
quelle
2
Möglicherweise möchten Sie das Wort "Suffix" in Ihrer Frage oder Ihrem Titel verwenden, um dies für andere Personen leichter zu finden. Ich bin mir nicht sicher, ob es dafür ein anderes Wort gibt, wenn ich über Daten spreche.
Harley Holcombe
Ausgezeichnete Frage. Ich habe das erst vor ein paar Tagen gedacht - sehr hilfreich.
RichH

Antworten:

278

Verwenden Sie die Ordinalisierungsmethode aus 'active_support'.

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

Hinweis: Wenn Sie IRB mit Ruby 2.0 verwenden, müssen Sie zuerst Folgendes ausführen:

require 'active_support/core_ext/integer/inflections'
Bartosz Blimke
quelle
15
Beachten Sie nur, dass dies nicht in der Standardbibliothek enthalten ist.
Chris Lloyd
97

Sie können die ordinale Hilfsmethode von active_support für Zahlen verwenden.

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

Wenn Sie die Antwort von Patrick McKenzie etwas weiter gehen, können Sie eine neue Datei in Ihrem config/initializersVerzeichnis mit dem Namen date_format.rb(oder was auch immer Sie wollen) erstellen und diese darin ablegen:

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

Dann können Sie in Ihrem Ansichtscode jedes Datum formatieren, indem Sie ihm einfach Ihr neues Datumsformat zuweisen:

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

Es ist einfach, es funktioniert und es ist leicht aufzubauen. Fügen Sie einfach weitere Formatzeilen in die Datei date_format.rb für jedes Ihrer verschiedenen Datumsformate ein. Hier ist ein ausführlicheres Beispiel.

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
quelle
7
Gute Antwort. Für Rails 3 hat sich ActiveSupport ziemlich verändert, daher ist das Folgende das Äquivalent: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
quelle
6

Ich mag Bartosz 'Antwort, aber hey, da es sich um Rails handelt, machen wir einen Schritt weiter. (Bearbeiten: Obwohl ich nur die folgende Methode monkeypatch wollte, stellt sich heraus, dass es einen saubereren Weg gibt.)

DateTimeInstanzen verfügen über eine to_formatted_svon ActiveSupport bereitgestellte Methode, die ein einzelnes Symbol als Parameter verwendet und, wenn dieses Symbol als gültiges vordefiniertes Format erkannt wird, einen String mit der entsprechenden Formatierung zurückgibt.

Diese Symbole werden definiert durch Time::DATE_FORMATS. Dies ist ein Hash von Symbolen für Zeichenfolgen für die Standardformatierungsfunktion ... oder 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

Aber hey, wenn Sie der Gelegenheit zum Monkeypatch nicht widerstehen können, können Sie dem immer eine sauberere Oberfläche geben:

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
quelle
3

Erstellen Sie Ihr eigenes %oFormat.

Initialisierer

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 }

Verwendung

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

Sie können dies auch mit Dateund verwenden 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"
Joshua Pinter
quelle
Nicht sicher, ob dies dokumentiert ist. Ich kann anscheinend keine Aufzeichnung davon finden, aber wir verwenden sie in unserer Codebasis, also müssen wir sie irgendwo gefunden haben.
Joshua Pinter
1
Ich bin nicht in der Lage, dies auf 2.6.3 zum Laufen zu bringen. Vielleicht war es in einer älteren Version von Ruby? Oder vielleicht jemand Affe Timein Ihrem Projekt gepatcht ?
Kcdragon
2
@kcdragon Wow, du hattest absolut recht. Durchsuchte die Codebasis und stellte fest, dass mein alter Freund Chuck Bergeron diesen Initialisierer vor fast 7 Jahren hinzugefügt hatte. Unabhängig davon finde ich dies immer noch sehr nützlich, daher habe ich die Antwort dahingehend aktualisiert, wie sie implementiert werden kann, wie wir sie in CNTRAL haben.
Joshua Pinter
2

Obwohl Jonathan Tran sagte, er suche zuerst nach dem abgekürzten Wochentag, gefolgt vom abgekürzten Monat, denke ich, dass es für Leute, die hier landen, nützlich sein könnte, zu wissen, dass Rails sofort mehr Unterstützung bietet häufig verwendbarer langer Monat, ordinale Tageszahl, gefolgt vom Jahr, wie in June 1st, 2018.

Es kann leicht erreicht werden mit:

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

Oder:

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

Sie können sich auch an eine Zeitinstanz halten, wenn Sie dies wünschen:

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

Weitere Formate und Kontexte zum Erstellen eines benutzerdefinierten Formats finden Sie in den Rails-API-Dokumenten .

Olivier Lacan
quelle