Rails ActiveRecord Datum zwischen

171

Ich muss Kommentare abfragen, die an einem Tag abgegeben wurden. Das Feld ist Teil der Standardzeitstempel, ist created_at. Das ausgewählte Datum stammt von adate_select .

Wie kann ich ActiveRecorddas machen?

Ich brauche so etwas wie:

"SELECT * FROM comments WHERE created_at BETWEEN '2010-02-03 00:00:00' AND '2010-02-03 23:59:59'"
Rtacconi
quelle

Antworten:

401

Nur ein Hinweis, dass die aktuell akzeptierte Antwort in Rails 3 veraltet ist. Sie sollten dies stattdessen tun:

Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)

Wenn Sie reine Zeichenfolgenbedingungen verwenden möchten oder müssen , können Sie Folgendes tun:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
quelle
9
Day.where (: reference_date => 6.months.ago..Time.now) funktioniert, danke
boulder_ruby
4
Würde dies nicht ein Objekt mit großer Reichweite erzeugen?
Kasper Grubbe
3
@ KasperGrubbe, wenn Sie den Bereich alleine verwenden würden, würde es, aber Rails verwendet nur den ersten und letzten Wert
Dex
4
@KasperGrubbe @Dex Das macht nicht Rails. Die Range-Klasse in Ruby speichert nur die unteren und oberen Grenzen. Dies läuft in irb gut: 1..1000000000000Ich bin mir nicht
Connor Clark,
11
+1 Wir können es auch zu einem Anwendungsbereich machen: scope :between, -> (a, b) { where(created_at: a..b) }
Rebagliatte
48

Ich würde persönlich einen Bereich erstellen, um ihn lesbarer und wiederverwendbarer zu machen:

In Ihrer Comment.rb können Sie einen Bereich definieren:

scope :created_between, lambda {|start_date, end_date| where("created_at >= ? AND created_at <= ?", start_date, end_date )}

Dann zur Abfrage erstellt zwischen:

@comment.created_between(1.year.ago, Time.now)

Ich hoffe es hilft.

Marshall Shen
quelle
4
Sehr sauberer Ansatz ... perfekt !!
Joseph N.
Zurück, um diese Antwort zu verbessern, da ich genau nach diesem Problem gesucht habe. Bei der Syntax falsch erraten, angenommen #between?, einen Bereich akzeptiert.
Tass
28

Rails 5.1 führte eine neue Datumshilfemethode ein all_day, siehe: https://github.com/rails/rails/pull/24930

>> Date.today.all_day
=> Wed, 26 Jul 2017 00:00:00 UTC +00:00..Wed, 26 Jul 2017 23:59:59 UTC +00:00

Wenn Sie Rails 5.1 verwenden, sieht die Abfrage folgendermaßen aus:

Comment.where(created_at: @selected_date.all_day)
Bismark
quelle
1
Herrlich. Dies ist tatsächlich Teil des ActiveSupport-Edelsteins (und anschließend des gesamten ActiveRecord-Ökosystems), sodass es auch außerhalb von Rails funktioniert! Nur require 'active_record'und du bist fertig!
Meister der Enten
24

Dieser Code sollte für Sie funktionieren:

Comment.find(:all, :conditions => {:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day})

Weitere Informationen finden Sie unter Zeitberechnungen

Hinweis: Dieser Code ist veraltet . Verwenden Sie den Code aus der Antwort, wenn Sie Rails 3.1 / 3.2 verwenden

Irukandji
quelle
Ok, aber aus dem Formular erhalte ich folgendes: {"geschrieben_at (4i)" => "18", "geschrieben_at (5i)" => "56", "Inhalt" => "rrrrrr", "geschrieben_at (1i)" = > "2010", "ritten_at (2i) "=>" 5 "," geschriebenes_at (3i) "=>" 4 "} Wie kann ich ein Objekt erstellen, um begin_of_day zu verwenden?
Rtacconi
Dies ist, was ich brauche: purab.wordpress.com/2009/06/16/…
rtacconi
2
Ich mag diese Methode gegenüber der akzeptierten Antwort, weil sie nicht auf einer date()Funktion auf DB-Ebene beruht . Es ist möglicherweise db unabhängiger.
Craig Walker
10

Ich habe diesen Code ausgeführt, um festzustellen, ob die überprüfte Antwort funktioniert, und musste versuchen, die Daten zu vertauschen, um sie richtig zu machen. Das hat funktioniert--

Day.where(:reference_date => 3.months.ago..Time.now).count
#=> 721

Wenn Sie der Meinung sind, dass die Ausgabe 36 hätte betragen sollen, denken Sie daran, Sir, wie viele Tage sind 3 Tage für 3 Personen?

boulder_ruby
quelle
6
Comment.find(:all, :conditions =>["date(created_at) BETWEEN ? AND ? ", '2011-11-01','2011-11-15'])
Kaushal Sharma
quelle
5

Ich habe die 3 Punkte anstelle von 2 verwendet. Drei Punkte geben Ihnen einen Bereich, der am Anfang offen und am Ende geschlossen ist. Wenn Sie also zwei Abfragen für nachfolgende Bereiche durchführen, können Sie nicht dieselbe Zeile zurückbekommen beide.

2.2.2 :003 > Comment.where(updated_at: 2.days.ago.beginning_of_day..1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" BETWEEN '2015-07-12 00:00:00.000000' AND '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 
2.2.2 :004 > Comment.where(updated_at: 2.days.ago.beginning_of_day...1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" >= '2015-07-12 00:00:00.000000' AND "comments"."updated_at" < '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 

Und ja, immer schön, ein Zielfernrohr zu benutzen!

nroose
quelle
4

Wenn Sie nur einen Tag haben möchten, ist dies einfacher:

Comment.all(:conditions => ["date(created_at) = ?", some_date])
klew
quelle
4

Es gibt verschiedene Möglichkeiten. Sie können diese Methode verwenden:

start = @selected_date.beginning_of_day
end = @selected_date.end_of_day
@comments = Comment.where("DATE(created_at) BETWEEN ? AND ?", start, end)

Oder dieses:

@comments = Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)
ben
quelle
4

Ich denke, es sollte ein standardmäßiges aktives Datensatzverhalten geben. Das Abfragen von Daten ist schwierig, insbesondere wenn Zeitzonen betroffen sind.

Wie auch immer, ich benutze:

  scope :between, ->(start_date=nil, end_date=nil) {
    if start_date && end_date
      where("#{self.table_name}.created_at BETWEEN :start AND :end", start: start_date.beginning_of_day, end: end_date.end_of_day)
    elsif start_date
      where("#{self.table_name}.created_at >= ?", start_date.beginning_of_day)
    elsif end_date
      where("#{self.table_name}.created_at <= ?", end_date.end_of_day)
    else
      all
    end
  }
Augustin Riedinger
quelle
1

Sie können unten Edelstein verwenden, um die Datensätze zwischen Daten zu finden,

Dieses Juwel ist recht einfach zu bedienen und klarer. Von Star verwende ich dieses Juwel und die API klarer und die Dokumentation auch gut erklärt.

Post.between_times(Time.zone.now - 3.hours,  # all posts in last 3 hours
                  Time.zone.now)

Hier könnten Sie auch unser Feld passieren Post.by_month("January", field: :updated_at)

Bitte lesen Sie die Dokumentation und probieren Sie es aus.

Jenorish
quelle