Rails ActiveRecord date entre

171

J'ai besoin d'interroger les commentaires faits en un jour. Le champ fait partie des horodatages standard, estcreated_at . La date sélectionnée provient d'un date_select.

Comment puis-je utiliser ActiveRecord pour faire ça?

J'ai besoin de quelque chose comme:

"SELECT * FROM comments WHERE created_at BETWEEN '2010-02-03 00:00:00' AND '2010-02-03 23:59:59'"
rtacconi
la source

Réponses:

402

Notez simplement que la réponse actuellement acceptée est obsolète dans Rails 3. Vous devriez plutôt faire ceci:

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

Ou, si vous voulez ou devez utiliser des conditions de chaîne pure , vous pouvez faire:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
la source
9
Day.where (: reference_date => 6.months.ago..Time.now) fonctionne, merci
boulder_ruby
4
Cela ne créerait-il pas un objet de grande portée?
Kasper Grubbe
3
@KasperGrubbe si vous utilisiez la plage seule, ce serait le cas, mais Rails utilise uniquement les première et dernière valeurs
Dex
4
@KasperGrubbe @Dex Ce n'est pas Rails qui fait ça. La classe Range dans Ruby enregistre uniquement les limites inférieure et supérieure. Cela fonctionne bien dans irb: 1..1000000000000je ne sais pas ce que vous entendez par `` utiliser la plage seule ''
Connor Clark
11
+1 On peut aussi en faire une portée: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte
48

Je créerais personnellement une portée pour la rendre plus lisible et réutilisable:

Dans votre Comment.rb, vous pouvez définir une portée:

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

Puis interroger créé entre:

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

J'espère que ça aide.

Marshall Shen
la source
4
Approche très propre ... parfait !!
Joseph N.
Revenez à voter pour cette réponse parce que j'ai recherché ce problème. Deviné incorrectement à la syntaxe, supposé #between?accepté une plage.
Tass
28

Rails 5.1 a introduit une nouvelle méthode d'assistance de date all_day, voir: 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

Si vous utilisez Rails 5.1, la requête ressemblerait à ceci:

Comment.where(created_at: @selected_date.all_day)
Bismark
la source
1
Glorieux. Cela fait en fait partie de la gemme ActiveSupport (et par la suite de tout l'écosystème ActiveRecord), donc cela fonctionne aussi en dehors de Rails! Juste require 'active_record'et vous êtes prêt!
Master of Ducks
24

Ce code devrait fonctionner pour vous:

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

Pour plus d'informations, consultez les calculs de temps

Remarque: ce code est obsolète . Utilisez le code de la réponse si vous utilisez Rails 3.1 / 3.2

Irukandji
la source
Ok mais à partir de la forme que j'obtiens: {"wrote_at (4i)" => "18", "écrit_at (5i)" => "56", "content" => "rrrrrr", "écrit_at (1i)" = > "2010", "wrote_at (2i)" => "5", "wrote_at (3i)" => "4"} Comment puis-je créer un objet à utiliser begin_of_day?
rtacconi
Voici ce dont j'ai besoin: purab.wordpress.com/2009/06/16/…
rtacconi
2
J'aime cette méthode par rapport à la réponse acceptée car elle ne repose pas sur une date()fonction au niveau de la base de données ; il est potentiellement plus indépendant de la base de données.
Craig Walker
10

J'ai exécuté ce code pour voir si la réponse vérifiée fonctionnait et j'ai dû essayer d'échanger les dates pour bien faire les choses. Cela a fonctionné -

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

Si vous pensez que la sortie aurait dû être de 36, considérez ceci, Monsieur, combien de jours est de 3 jours pour 3 personnes?

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

J'ai utilisé les 3 points, au lieu de 2. Trois points vous donnent une plage qui est ouverte au début et fermée à la fin, donc si vous faites 2 requêtes pour les plages suivantes, vous ne pouvez pas récupérer la même ligne tous les deux.

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 []> 

Et, oui, toujours agréable d'utiliser une lunette!

nez
la source
4

Si vous ne voulez obtenir qu'un jour, ce serait plus facile de cette façon:

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

il y a plusieurs manières. Vous pouvez utiliser cette méthode:

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

Ou ca:

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

Il devrait y avoir un comportement d'enregistrement actif par défaut à ce sujet, je pense. L'interrogation des dates est difficile, en particulier lorsque des fuseaux horaires sont impliqués.

Quoi qu'il en soit, j'utilise:

  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
la source
1

Vous pouvez utiliser la gemme ci-dessous pour trouver les enregistrements entre les dates,

Ce bijou assez simple d'utilisation et plus clair Par star j'utilise ce bijou et l'API plus clair et la documentation également bien expliquée.

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

Ici, vous pouvez également passer notre champ Post.by_month("January", field: :updated_at)

Veuillez consulter la documentation et l'essayer.

Jenorish
la source