Rails ActiveRecord fecha entre

171

Necesito consultar los comentarios realizados en un día. El campo es parte de las marcas de tiempo estándar, es created_at. La fecha seleccionada proviene de a date_select.

¿Cómo puedo usar ActiveRecordpara hacer eso?

Necesito algo como:

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

Respuestas:

402

Solo una nota de que la respuesta actualmente aceptada está en desuso en Rails 3. En su lugar, debe hacer esto:

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

O, si quiere o tiene que usar condiciones de cadena pura , puede hacer:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
fuente
9
Day.where (: reference_date => 6.months.ago..Time.now) funciona, gracias
boulder_ruby
44
¿No crearía esto un objeto de gran alcance?
Kasper Grubbe
3
@KasperGrubbe si usaras el rango por sí mismo, pero Rails solo usa el primer y último valor
Dex
44
@KasperGrubbe @Dex No es Rails quien hace eso. La clase Range en Ruby solo guarda los límites inferior y superior. Esto funciona bien en irb: 1..1000000000000no estoy claro a qué te refieres con 'usar el rango por sí mismo'
Connor Clark
11
+1 También podemos convertirlo en un alcance: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte
48

Personalmente, creé un ámbito para hacerlo más legible y reutilizable:

En su Comment.rb, puede definir un alcance:

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

Luego para consultar creado entre:

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

Espero eso ayude.

Marshall Shen
fuente
44
Enfoque muy limpio ... perfecto !!
Joseph N.
Vuelva a votar esta respuesta porque busqué este mismo problema. Adivinado incorrectamente en la sintaxis, asumió que #between?aceptaba un rango.
Tass
28

Rails 5.1 introdujo un nuevo método de ayuda de fecha all_day, consulte: 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 está utilizando Rails 5.1, la consulta se vería así:

Comment.where(created_at: @selected_date.all_day)
Bismark
fuente
1
Glorioso. En realidad, esto es parte de la gema ActiveSupport (y, posteriormente, todo el ecosistema ActiveRecord), por lo que también funciona fuera de Rails. Justo require 'active_record'y ya está todo listo!
Master of Ducks
24

Este código debería funcionar para usted:

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

Para obtener más información, eche un vistazo a los cálculos de tiempo

Nota: este código está en desuso . Use el código de la respuesta si está usando Rails 3.1 / 3.2

Irukandji
fuente
Ok, pero del formulario obtengo esto: {"written_at (4i)" => "18", "written_at (5i)" => "56", "content" => "rrrrrr", "written_at (1i)" = > "2010", "written_at (2i)" => "5", "written_at (3i)" => "4"} ¿Cómo puedo construir un objeto para usar begin_of_day?
rtacconi
Esto es lo que necesito: purab.wordpress.com/2009/06/16/…
rtacconi
2
Me gusta este método sobre la respuesta aceptada porque no se basa en una date()función de nivel db ; es potencialmente más independiente de db.
Craig Walker
10

Ejecuté este código para ver si la respuesta marcada funcionaba, y tuve que intentar cambiar las fechas para hacerlo bien. Esto funcionó

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

Si está pensando que el resultado debería haber sido 36, considere esto, señor, ¿cuántos días son 3 días para 3 personas?

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

He estado usando los 3 puntos, en lugar de 2. Tres puntos le dan un rango que está abierto al principio y cerrado al final, por lo que si hace 2 consultas para los rangos posteriores, no puede volver a obtener la misma fila ambos.

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

Y sí, ¡siempre es bueno usar un osciloscopio!

nroose
fuente
4

Si solo desea obtener un día, sería más fácil de esta manera:

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

Hay varias formas. Puedes usar este método:

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

O esto:

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

Creo que debería haber un comportamiento de registro activo predeterminado en esto. Consultar fechas es difícil, especialmente cuando hay zonas horarias involucradas.

De todos modos, yo uso:

  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
fuente
1

Podrías usar la gema debajo para encontrar los registros entre fechas,

Esta gema es bastante fácil de usar y más clara Por estrellas estoy usando esta gema y la API más clara y la documentación también está bien explicada.

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

Aquí también puedes pasar nuestro campo Post.by_month("January", field: :updated_at)

Por favor, consulte la documentación y pruébelo.

Jenorish
fuente