Rails ActiveRecord วันที่ระหว่าง


171

ฉันต้องการสอบถามความคิดเห็นที่เกิดขึ้นในหนึ่งวัน created_atสนามเป็นส่วนหนึ่งของการประทับเวลาที่มาตรฐานคือ date_selectวันที่ที่เลือกมาจาก

ฉันActiveRecordจะใช้ทำสิ่งนั้นได้อย่างไร

ฉันต้องการบางสิ่งเช่น:

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

คำตอบ:


402

โปรดทราบว่าคำตอบที่ยอมรับในปัจจุบันนั้นไม่รองรับใน Rails 3 คุณควรทำสิ่งนี้แทน:

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

หรือถ้าคุณต้องการหรือต้องใช้เงื่อนไขสตริงบริสุทธิ์คุณสามารถทำสิ่งต่อไปนี้

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) ใช้ได้ขอบคุณ
boulder_ruby

4
สิ่งนี้จะไม่สร้างวัตถุขนาดใหญ่หรือไม่
Kasper Grubbe

3
@KasperGrubbe หากคุณใช้ช่วงด้วยตัวมันเอง แต่ Rails จะใช้ค่าแรกและค่าสุดท้าย
Dex

4
@KasperGrubbe @Dex ไม่ใช่ Rails ที่ทำเช่นนั้น คลาส Range ใน Ruby จะบันทึกขอบเขตล่างและบนเท่านั้น หรูนี้วิ่งในคณะกรรมการ: 1..1000000000000ฉันไม่มีความชัดเจนในสิ่งที่คุณหมายถึงโดย 'ใช้ช่วงด้วยตัวเอง'
คอนเนอร์คลาร์ก

11
+1 เราสามารถทำให้เป็นขอบเขต: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte

48

ฉันจะสร้างขอบเขตส่วนตัวเพื่อให้สามารถอ่านและใช้งานได้มากขึ้น:

ใน Comment.rb คุณคุณสามารถกำหนดขอบเขต:

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

จากนั้นแบบสอบถามที่สร้างขึ้นระหว่าง:

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

หวังว่ามันจะช่วย


4
วิธีการที่สะอาดมาก ... สมบูรณ์แบบ !!
โจเซฟเอ็น

กลับไปที่ upvote คำตอบนี้เพราะฉันค้นหาปัญหานี้มาก เดาไม่ถูกต้องที่ไวยากรณ์ถือว่า#between?ยอมรับช่วง
Tass

28

Rails 5.1 แนะนำวิธีการช่วยเหลือแบบall_dayใหม่ดูได้ที่: 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

หากคุณใช้ Rails 5.1 เคียวรีจะมีลักษณะดังนี้:

Comment.where(created_at: @selected_date.all_day)

1
รุ่งโรจน์. นี่เป็นส่วนหนึ่งของ ActiveSupport gem (และต่อมาเป็นระบบนิเวศ ActiveRecord ทั้งหมด) ดังนั้นจึงสามารถใช้งานกับ Rails ได้เช่นกัน! เพียงแค่require 'active_record'คุณพร้อมแล้ว!
ปริญญาโทเป็ด

24

รหัสนี้ควรใช้กับคุณ:

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

สำหรับข้อมูลเพิ่มเติมดูได้ที่ คำนวณเวลา

หมายเหตุ:รหัสนี้จะเลิกใช้ ใช้รหัสจากคำตอบหากคุณใช้ Rails 3.1 / 3.2


ตกลง แต่จากแบบฟอร์มที่ฉันได้รับ: {"write_at (4i)" => "18", "write_at (5i)" => "56", "เนื้อหา" => "rrrrrr", "write_at (1i)" = > "2010", "write_at (2i)" => "5", "write_at (3i)" => "4"} ฉันจะสร้างวัตถุเพื่อใช้กับ initial_of_day ได้อย่างไร?
rtacconi

นี่คือสิ่งที่ฉันต้องการ: purab.wordpress.com/2009/06/16/…
rtacconi

2
ฉันชอบวิธีนี้มากกว่าคำตอบที่ยอมรับเพราะไม่ได้อาศัยdate()ฟังก์ชั่นระดับ db ; มันอาจ db อิสระมากขึ้น
Craig Walker

10

ฉันใช้รหัสนี้เพื่อดูว่าคำตอบที่ตรวจสอบนั้นใช้ได้หรือไม่และต้องลองสลับวันที่เพื่อให้ถูกต้อง สิ่งนี้ได้ผล -

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

หากคุณคิดว่าผลลัพธ์ควรจะเป็น 36 ลองพิจารณาดูสิคุณจะได้ 3 วันถึง 3 คนกี่วัน?



5

ฉันใช้จุด 3 จุดแทน 2 จุดสามจุดจะให้ช่วงที่เปิดอยู่ที่จุดเริ่มต้นและปิดท้ายดังนั้นถ้าคุณทำแบบสอบถาม 2 ข้อสำหรับช่วงต่อมาคุณจะไม่สามารถกลับแถวเดิมกลับมาได้ ทั้งสอง

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

และใช่เสมอดีที่จะใช้ขอบเขต!


4

หากคุณต้องการได้หนึ่งวันมันจะง่ายขึ้นด้วยวิธีนี้:

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

4

มีหลายวิธี คุณสามารถใช้วิธีนี้:

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

หรือสิ่งนี้:

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

4

ควรจะมีพฤติกรรมการบันทึกที่ใช้งานเริ่มต้นในสิ่งนี้ฉันคิดว่า การสืบค้นวันที่ทำได้ยากโดยเฉพาะอย่างยิ่งเมื่อมีส่วนร่วมของเขตเวลา

อย่างไรก็ตามฉันใช้:

  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

คุณสามารถใช้อัญมณีด้านล่างเพื่อค้นหาบันทึกระหว่างวันที่

อัญมณีนี้ใช้งานง่ายและชัดเจนยิ่งขึ้นโดย Star am ใช้ gem นี้และ API ที่ชัดเจนยิ่งขึ้นและเอกสารอธิบายยังอธิบายได้ดี

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

ที่นี่คุณสามารถผ่านสนามของเราด้วย Post.by_month("January", field: :updated_at)

โปรดดูเอกสารและลอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.