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'"

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)

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.


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)

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


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?


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

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!


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

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)

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
  }

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.