简体   繁体   中英

What is the Rails way to define tomorrow's date?

In a Rails 3.2 app, I have a query defined to return all Event items with :due_date equal to today.

@due_today = Event.where(:due_date => Time.now.beginning_of_day..Time.now.end_of_day)

I want to modify this to return all events due today and tomorrow.

What is the best way to do this?

I know there are several options available to me:

Date.tomorrow
Date.current.tomorrow
Date.now.tomorrow
DateTime.now.tomorrow.to_date
Time.now.tomorrow.to_date
Date.current+1

I'm sure there are others. Are all of these interchangeable? Are there any differences in performance? Are there any issues associated with different approaches? I'd welcome any suggestions as to which is the best way to do this.

For extra kudos: I also want to display the :due_date as Today HH:MM or Tomorrow HH:MM, where HH:MM is the time. Is there a method baked in to Rails to display dates as Today or Tomorrow? Or will I need to define my own scope?

Many thanks!

Benchmarking these, I get:

N = 100000
Benchmark.bmbm do |test|
  test.report("Date.tomorrow") do
    N.times do
      x = Date.tomorrow
    end
  end
  test.report("Date.current.tomorrow") do
    N.times do
      x = Date.current.tomorrow
    end
  end
  # test.report("Date.now.tomorrow") # => Coughs up an exception, Date.now doesn't exist!
  test.report("DateTime.now.tomorrow.to_date") do
    N.times do 
      x = DateTime.now.tomorrow.to_date
    end    
  end
  test.report("Time.now.tomorrow.to_date") do
    N.times do
      x = Time.now.tomorrow.to_date
    end
  end
  test.report("Date.current+1") do
    N.times do
      x = Date.current+1
    end
  end
  test.report("DateTime.tomorrow") do
    N.times do 
      x = DateTime.now
    end    
  end
end

Results:

Rehearsal -----------------------------------------------------------------
Date.tomorrow                   1.640000   0.010000   1.650000 (  1.662668)
Date.current.tomorrow           1.580000   0.000000   1.580000 (  1.587714)
DateTime.now.tomorrow.to_date   0.360000   0.010000   0.370000 (  0.363281)
Time.now.tomorrow.to_date       4.270000   0.010000   4.280000 (  4.303273)
Date.current+1                  1.580000   0.010000   1.590000 (  1.590406)
DateTime.tomorrow               0.160000   0.000000   0.160000 (  0.164075)
-------------------------------------------------------- total: 9.630000sec

                                    user     system      total        real
Date.tomorrow                   1.590000   0.000000   1.590000 (  1.601091)
Date.current.tomorrow           1.610000   0.010000   1.620000 (  1.622415)
DateTime.now.tomorrow.to_date   0.310000   0.000000   0.310000 (  0.319628)
Time.now.tomorrow.to_date       4.120000   0.010000   4.130000 (  4.145556)
Date.current+1                  1.590000   0.000000   1.590000 (  1.596724)
DateTime.tomorrow               0.140000   0.000000   0.140000 (  0.137487)

From your list of suggestions, DateTime.now.tomorrow.to_date is faster.

Check out the last option I've added though, it returns a Date object and is the fastest of the bunch by a country mile. It's also one of the most human-readable from the list.

Assuming you're using MYSQL, your query might be faster if you use MySQL's BETWEEN() function:

@due_today = Event.where("due_date BETWEEN ? AND ?", DateTime.today, DateTime.tomorrow)

Although I'm not sure if you have indexes on events.due_date or if BETWEEN will still use these. You'll have to benchmark both to see which is quicker with a large DATA set.

Hope that helps?

How about this?

1.day.from_now
2.days.from_now
3.days.from_now

If you want to increment given time..

1.day.from_now(start_time) # gives a day after the start time 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM