I have an app where there is always a current contest (defined by start_date and end_date datetime). I have the following code in the application_controller.rb as a before_filter.
def load_contest
@contest_last = Contest.last
@contest_last.present? ? @contest_leftover = (@contest_last.end_date.utc - Time.now.utc).to_i : @contest_leftover = 0
if @contest_last.nil?
Contest.create(:start_date => Time.now.utc, :end_date => Time.now.utc + 10.minutes)
elsif @contest_leftover < 0
@winner = Organization.order('votes_count DESC').first
@contest_last.update_attributes!(:organization_id => @winner.id, :winner_votes => @winner.votes_count) if @winner.present?
Organization.update_all(:votes_count => 0)
Contest.create(:start_date => @contest_last.end_date.utc, :end_date => Time.now.utc + 10.minutes)
end
end
My questions:
1) I would like to change the :end_date to something that signifies next Sunday at a certain time (eg. next Sunday at 8pm). Similarly, I could then set the :start_date to to the previous Sunday at a certain time. I saw that there is a sunday() class (http://api.rubyonrails.org/classes/Time.html#method-i-sunday), but not sure how to specify a certain time on that day.
2) For this situation of always wanting the current contest, is there a better way of loading it in the app? Would caching it be better and then reloading if a new one is created? Not sure how this would be done, but seems to be more efficient.
Thanks!
Start with this snippet. In rails, given a date/time object d
, the expression
d - wday.day
Gives the last Sunday not after that date. i.e. if the day itself is a Sunday the result will be d.
Then to get the next sunday:
sunday1 = d - wday.day
sunday2 = sunday1 + 7.day
And to set the times for both:
sunday1 = (d - wday.day).change(:hour => 8,:min => 30)
sunday2 = (sunday1 + 7.day).change(:hour => 20)
No need for any external modules. Rails (but not core ruby!) has all the date/time manipulation functionality you need.
Note how the change
function works: if you pass it :hour
only, it will reset the minute and second to 0. If you pass it :hour
and :minute
, it will reset only the second. See the docs for details.
One last thing: be mindful of what time zone you are using.