Rails ActiveRecord ngày giữa


171

Tôi cần truy vấn ý kiến ​​được thực hiện trong một ngày. Trường này là một phần của dấu thời gian tiêu chuẩn created_at. Ngày đã chọn đến từ a date_select.

Làm thế nào tôi có thể sử dụng ActiveRecordđể làm điều đó?

Tôi cần một cái gì đó như:

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

Câu trả lời:


402

Chỉ cần lưu ý rằng câu trả lời hiện được chấp nhận không được chấp nhận trong Rails 3. Thay vào đó, bạn nên làm điều này:

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

Hoặc, nếu bạn muốn hoặc phải sử dụng các điều kiện chuỗi thuần túy , bạn có thể thực hiện:

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) hoạt động, cảm ơn
boulder_ruby

4
Điều này sẽ không tạo ra một đối tượng phạm vi lớn?
Kasper Grubbe

3
@KasperGrubbe nếu bạn đã sử dụng phạm vi của chính nó, nhưng Rails chỉ sử dụng các giá trị đầu tiên và cuối cùng
Dex

4
@KasperGrubbe @Dex Không phải là Rails làm điều đó. Lớp Range trong Ruby chỉ lưu các giới hạn dưới và trên. Điều này chạy tốt trong irb: 1..1000000000000Tôi không rõ ý của bạn là gì khi 'sử dụng phạm vi của chính nó'
Connor Clark

11
+1 Chúng tôi cũng có thể biến nó thành một phạm vi: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte

48

Cá nhân tôi sẽ tạo ra một phạm vi để làm cho nó dễ đọc hơn và có thể sử dụng lại:

Trong bạn Comment.rb, bạn có thể xác định một phạm vi:

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

Sau đó, truy vấn được tạo giữa:

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

Hy vọng nó giúp.


4
Cách tiếp cận rất sạch sẽ ... hoàn hảo !!
Joseph N.

Quay lại upvote câu trả lời này bởi vì tôi đã tìm kiếm chính vấn đề này. Đoán không chính xác theo cú pháp, giả định #between?chấp nhận một phạm vi.
Tass

28

Rails 5.1 đã giới thiệu một phương thức trợ giúp ngày mới all_day, xem: 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

Nếu bạn đang sử dụng Rails 5.1, truy vấn sẽ như sau:

Comment.where(created_at: @selected_date.all_day)

1
Vinh quang. Đây thực sự là một phần của đá quý ActiveSupport (và sau đó là toàn bộ hệ sinh thái ActiveRecord), vì vậy nó cũng hoạt động bên ngoài Rails! Chỉ require 'active_record'và bạn đã sẵn sàng!
Bậc thầy của vịt

24

Mã này sẽ làm việc cho bạn:

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

Để biết thêm thông tin, hãy xem tính toán thời gian

Lưu ý: Mã này không được dùng nữa . Sử dụng mã từ câu trả lời nếu bạn đang sử dụng Rails 3.1 / 3.2


Ok nhưng từ mẫu tôi nhận được điều này: {"write_at (4i)" => "18", "write_at (5i)" => "56", "content" => "rrrrrr", "write_at (1i)" = > "2010", "write_at (2i)" => "5", "write_at (3i)" => "4"} Làm cách nào tôi có thể xây dựng một đối tượng để sử dụng start_of_day?
rtacconi

Đây là những gì tôi cần: purab.wordpress.com/2009/06/16/ từ
rtacconi

2
Tôi thích phương pháp này hơn câu trả lời được chấp nhận vì nó không dựa vào date()hàm mức db ; nó có khả năng độc lập hơn db.
Craig Walker

10

Tôi đã chạy mã này để xem câu trả lời đã được kiểm tra có hoạt động hay không và phải thử hoán đổi xung quanh các ngày để làm cho đúng. Điều này đã làm việc--

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

Nếu bạn đang nghĩ đầu ra phải là 36, hãy xem xét điều này, thưa bạn, 3 ngày là 3 ngày cho 3 người?



5

Tôi đã sử dụng 3 dấu chấm, thay vì 2. Ba dấu chấm cung cấp cho bạn một phạm vi mở ở đầu và đóng ở cuối, vì vậy nếu bạn thực hiện 2 truy vấn cho các phạm vi tiếp theo, bạn không thể lấy lại cùng một hàng cả hai.

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

Và, vâng, luôn luôn tốt đẹp để sử dụng một phạm vi!


4

Nếu bạn chỉ muốn có được một ngày, nó sẽ dễ dàng hơn theo cách này:

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

4

có một số cách Bạn có thể sử dụng phương pháp này:

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

Hoặc này:

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

4

Cần phải có một hành vi ghi lại hoạt động mặc định về điều này tôi nghĩ. Truy vấn ngày là khó khăn, đặc biệt là khi các múi giờ có liên quan.

Dù sao, tôi sử dụng:

  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

Bạn có thể sử dụng đá quý dưới đây để tìm các bản ghi giữa các ngày,

Viên ngọc này khá dễ sử dụng và rõ ràng hơn Bởi vì sao đang sử dụng loại đá quý này và API rõ ràng hơn và tài liệu cũng được giải thích rõ ràng.

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

Ở đây bạn cũng có thể vượt qua lĩnh vực của chúng tôi Post.by_month("January", field: :updated_at)

Xin vui lòng xem tài liệu và thử nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.