Rails, ActiveRecord, Finding all events that fall on weekend - ruby-on-rails

I was Wondering if someone could help with this ActiveRecord query. I have Events that have a start and end date. I wanted to run a cron job that gets all events every Thursday that fall on the coming weekend.
Something like...
#events = Event.where("start_date <= ?", (Date.today + 3.days)).where("end_date >= ?", (Date.today + 3.days))
I know the above is incorrect, but hoping someone can perhaps enlighten me on an easier way to find the events for this query... Thanks in advance!

If I try to translate your question to an algorithm I think that what you are after is this: find all events which have the start_date during or before the coming weekend (i.e. before the weekend ends) and the end_date during or after the coming weekend (i.e. after the weekend starts). That way we'll find events that cover, at least partially, the weekend days.
If you run your rake on Thursdays, then the next weekend can be retrieved as this:
weekend_start = Date.today.end_of_week - 1 # the Saturday's date
weekend_end = Date.today.end_of_week # the Sunday's date
With this, the query is easy:
#events = Event.where("start_date <= ? AND end_date >= ?", weekend_end, weekend_start)
If your start_date and end_date columns were not DATE but DATETIME columns, you would have to define the start and end of weekend like the following instead:
weekend_start = Time.zone.now.end_of_week.midnight - 1.day # 00:00 at Saturday
weekend_end = Time.zone.now.end_of_week # 23:59 at Sunday
The definitions are using Time.zone to calculate the times in the local time zone.

We can find start time and end time of next weekends, so the query will be easy after that.
# Start weekends time
start_next_saturday = Date.today.end_of_week.at_beginning_of_day - 1.days
# End weekends time
end_next_sunday = Date.today.end_of_week.at_end_of_day
arel_table = Event.arel_table
#events = Event.where(arel_table[:start_date].lteq(end_next_sunday)
.and(arel_table[:end_date].gteq(start_next_saturday)))
Btw, Date.today + 3.days maybe an incorrect approach, so find the weekends time with above logic is more accurate!

try this
Event.where(created_at: (Date.today.end_of_week-1..Date.today.end_of_week))

Related

Rails 5 active record query where date range overlaps with other date range

I have a model with planting_date_begin and planting_date_end. I want to retrieve all records where any date in planting_date_begin..planting_date_end overlap with the range for the current_week
example:
if planting_date_begin: 3/5/2017 and planting_date_end: 3-12/2017
and this week is 3/26/2017-4/1/2017 it is not included in query.
if planting_date_begin: 3/1/2017 and planting_date_end: 4/15/2017 it would be included.
I set current_week range:
today = Date.today
days_in_week = today.at_beginning_of_week..today.at_end_of_week
This syntax is not right but I want to do something like:
Planting.where((planting_date_begin..planting_date_end).overlaps?(days_in_week) )
What is a succinct way to handle this? Incidentally, I am using postgres in case there is a way to do it differently.
Maybe not as succinct, but I have to do this a lot in a current project and my method is...
start_date = Date.today.at_beginning_of_week
end_date = Date.today.at_end_of_week
#plantings = Planting.where('planting_date_end >= ? AND planting_date_begin <= ?', start_date, end_date)
This covers all overlaps.. if planting starts before the range and ends after the range, if planting starts during the range, if planting ends during the range.

Ruby, check if date is a weekend?

I have a DailyQuote model in my rails application which has a date and price for a stock. Data in the database has been captured for this model including weekends. The weekend price values have been set as 0.
I want to change all the weekend prices for Saturday and Sunday to whatever the price was on Friday. What is the best way to do this in Ruby? To identify if a date falls on a Sat or Sun and change its value to the Fri of that weekend?
TFM shows an interesting way to identifying the day of the week:
t = Time.now
t.saturday? #=> returns a boolean value
t.sunday? #=> returns a boolean value
The simplest approach:
today = Date.today
if today.saturday? || today.sunday?
puts "Today is a weekend!"
end
You can also do this for any other day of the week. Ruby is fantastic and offers a lot of cool methods like this. I suggest when you get stumped take a look at what's available to the class by running .methods on it. So if you run Date.today.methods you will see these available.
require 'date'
today = Date.today
ask_price_for = (today.wday == 6) ? today - 1 : (today.wday == 0) ? today - 2 : today
or
require 'date'
today = Date.today
ask_price_for = (today.saturday?) ? today - 1 : (today.sunday?) ? today - 2 : today
ask_price_for now holds a date for which you would want to ask the price for.
Getting the actual price which is corresponding to you date depends on your Model and your ORM-Library (i.e. ActiveRecord).
class Time
def is_weekend?
[0, 6, 7].include?(wday)
end
end
time = Time.new
puts "Current Time : " + time.inspect
puts time.is_weekend?
since rails v5:
Date.current.on_weekend?
References:
api-doc
rails docu
Date.today.instance_eval { saturday? || sunday? }
Checking of weekend days (Saturday and Sunday) in the range of two dates in ruby
weekend_days = [0,6]
if (start_date.to_date..end_date.to_date).to_a.select {|k| weekend_days.include?(k.wday)}.present?
# you code
end

Rails 3.1: Querying Postgres for records within a time range

In my app I have a Person model. Each Person has an attribute time_zone that specifies their default time zone. I also have an Event model. Each Event has a start_time and end_time timestamp, saved in a Postgres database in UTC time.
I need to create a query that finds events for a particular person that fall between midnight of one day and midnight of the next. The #todays_events controller variable hold the results of the query.
Part of the reason that I'm taking this approach is that I may have people from other time zones looking at the list of events for a person. I want them to see the day as the person would see the day and not based on the time zone they are in as an observer.
For whatever reason, I'm still getting some events from the previous day in my result set for #todays_events. My guess is that I'm comparing a UTC timestamp with a non-UTC parameter, or something along those lines. Generally, only events that begin or end in the evening of the previous day show up on the query result list for today.
Right now, I'm setting up:
#today = Time.now.in_time_zone(#person.time_zone).midnight.to_date
#tomorrow = (#today + 1.day ).to_datetime
#today = #today.to_datetime
My query looks like:
#todays_activities = #person.marks.where("(start_time >= ? AND start_time < ?) OR (end_time >= ? AND end_time < ?);", #today, #tomorrow, #today, #tomorrow ).order("start_time DESC")
How should I change this so that I'm guaranteed only to receive results from today (per the #person.time_zone in the #todays_activities query?
You're losing track of your timezones when you call to_date so don't do that:
#today = Time.now.in_time_zone(#person.time_zone).midnight.utc
#tomorrow = #today + 1.day
When you some_date.to_datetime, you get a DateTime instance that is in UTC so the result of something like this:
Time.now.in_time_zone(#person.time_zone).midnight.to_date.to_datetime
will have a time-of-day of 00:00:00 and a time zone of UTC; the 00:00:00 is the correct time-of-day in #person.time_zone but not right for UTC (unless, of course, #person is in in the +0 time zone).
And you could simplify your query with overlaps:
where(
'(start_time, end_time) overlaps (timestamp :today, timestamp :tomorrow)',
:today => #today, :tomorrow => #tomorrow
)
Note that overlaps works with half-open intervals:
Each time period is considered to represent the half-open interval start <= time < end, unless start and end are equal in which case it represents that single time instant.

Rails: Is there away to get the Date object that is the closest Monday to today?

Given a date, how do I find the nearest Monday in Rails?
I know I can do things like:
Date.tomorrow
Date.today
Is there something like Date.nearest :monday ?
The commercial method on the Date object will let you do this. This example will get you the next Monday.
Date.commercial(Date.today.year, 1+Date.today.cweek, 1)
If you need the next or previous Monday, whichever is closest, you can do:
Date.commercial(Date.today.year, Date.today.cwday.modulo(4)+Date.today.cweek, 1)
I can't execute this right now, so forgive me if there are syntax errors.
It's a little bit tricky, but not so hard to calculate.
Use ActiveSupport::DateAndTimeCalculations#end_of_week to calculate end of a week, this method accepts a start_day parameter that is used to indicate start day of the week (it's :monday by default). They even have implemented sunday method.
The trick is the following: if you want to calculate closest Monday, you may calculate it as a end of the week which starts on Tuesday (Tue => 1st day, Wed => 2nd day, ..., Mon => 7th day which is also end of the week).
So all you need to do is:
# it will return current date if today is Monday and nearest Monday otherwise
Date.today.end_of_week(:tuesday)
I know this is an old thread but it's always nice to keep it current for future seekers.
Let's assume today is say Friday the 19th of August. All I do to get my nearest Monday is this:
monday = Date.today.monday
Then from there you can go back a week or forward a week like this:
last_monday = monday.last_week
next_monday = monday.next_week
Assuming you want both directions: Date.today.beginning_of_week + 7*(Date.today.wday/5)
Untested, so you might need to finetune, but here you go:
def Date.nearest_monday
today = Date.today
wday = today.wday
if wday > 4 # over the half of the week
today + (7 - wday) # next monday
else
today - (1 + wday) # previous monday
end
end

Generate Time object given weekday and minutes since midnight

I'm trying to generate a Time object initialized to the next instance of a specific weekday and number of minutes past midnight.
My data (representing a schedule) looks like: weekday, start, finish. Weekday is the day of the week between 0 and 6, and start/finish are integers representing minutes past midnight on that particular weekday.
What I'd like to be able to do is get a Time object for the next time that this will be so that I can work more flexibly with the start/end times for frontend purposes.
Does anyone know how to do this? I've tinkered with Time.utc without much success.
Not sure if I'm interpreting this correctly... Is it where given a weekday, you will find the next available date that is on that weekday? For example, if today is tuesday, and your schedule is set for thursday, then the time object will be at midnight on this thursday? If that's the case, something like this should work:
day_difference = #weekday - Time.now.wday
# If the difference is in the past, then add 7 so that it is next week.
if day_difference < 0
day_difference = day_difference + 7
end
next_date = Time.now.midnight + day_difference.days
start_time = next_date + #start.minutes
end_time = next_date + #finish.minutes
Where weekday is the value in your Schedule object. Once again, I'm not 100% sure what you're asking. Here start_time and end_time are time objects representing the next weekday with the corresponding amount of minutes added to them.
You can do something basic along these lines for this with something like the following:
class Schedule
attr_accessor :day_of_week, :start_minute, :finish_minute
def start(current_date = Time.zone.now)
current_date.beginning_of_week + day_of_week.days + start_minute.minutes
end
def finish(current_date = Time.zone.now)
current_date.beginning_of_week + day_of_week.days + finish_minute.minutes
end
def length
(finish_minute - start_minute).minutes
end
end
Since that's pretty rudimentary and I'm not sure exactly what you're looking to use it for, I suggest looking at some of the libraries mentioned in this post ice_cube, and business_time look like they're applicable for what you might be wanting

Resources