Finding records between date range - ruby-on-rails

I'm trying to find records whose start and end date range over a particular date. Date is random and :start_date and :end_date are attributes of the prices entity.
date = Time.now
record_i_want = Price.where(date => :start_date .. :end_date)
Thank you.

You can simply do
Price.where(:date => start_date..end_date)
This will result in the following SQL( for start and end dates - '2014-03-27', '2014-03-28')
SELECT `prices`.* FROM `prices` WHERE (`prices`.`date` BETWEEN '2014-03-27' AND '2014-03-28')
EDIT:
Realized that this is the query you are looking for. Thanks, Coenwulf for pointing it out
Price.where(['start_date < ? AND end_date > ?', date, date])

You want to select rows where your date is greater than the start_date and less than the end_date. You can specify the appropriate SQL where clause parameterized in your call to where like so:
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today})
That will give you all the prices that match. If you know you'll get only one you can get it by calling first.
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today}).first
Make any appropriate adjustment to the >= and <= if you want to exclude the start_date and/or the end_date from the results. If for example the Price is valid starting on the start_date but isn't valid through the end_date you can change the clause to:
":date >= start_date AND :date < end_date"

This should work:
def get_record_by_date(date)
Price.where([start_date.to_i < date.to_i] && [end_date.to_i > date.to_i])
end

Related

Datetime may not intersect other datetime for that user's activity

Might be a somewhat specific situation. And I kinda know how to do it in PHP/MySQL. But I was wondering if there was a faster way to do the following scenario:
A user has activities with a start- and end_date. (The activity starts at 12-10-2013 12:00:00 and ends at 12-10-2013 12:15:00 for example.)
Whenever the user creates a new activity. I want to check all the activities the user is part of(user has_many: activities) and see if none of the dates intersect with the date given for the new activity.
Since I'm pretty new to Rails I really don't know where to start searching for date comparisons and all...
Thanks in advance
An overlap is defined as another activity for which the end date is greater than or equal to the new activity's start date, and for which the start date is less than or equal to the new activity's end date.
Since you only want to detect whether such a record already exists, an appropriate test would be:
if Activity.where("starts_at <= ?" , new_activity_end_date ).
where("ends_at >= ?" , new_activity_start_date).
exists?
You can use regular comparators for date/times in Ruby (ie: >, < and ==).
Something like the following should do what you are looking for:
if current_user.activities.where("(starts_at <= ? AND ends_at >= ?) OR (starts_at >= ? AND starts_at <= ?)", start_datetime, start_datetime, start_datetime, end_datetime).count
# There exist activities that fall between start_datetime and end_datetime
else
# There exist no such activities
end
(starts_at <= start_datetime AND ends_at >= start_datetime) checks whether an event starts before and ends after start_datetime.
(starts_at >= start_datetime AND starts_at <= end_datetime) checks whether an event starts between start_datetime and end_datetime.
We must check that all this three kinds of intersection do not happen:
our activity must not happen within another activity
our activity must not start before another ends
our activity must not ends after another starts
We can do that using something like this:
class Activity < ActiveRecord::Base
validate :must_not_be_intersected
def intersected?
params = {
:start => start_date,
:end => end_date
}
Activity::where('start_date <= :start AND end_date >= :end', params)
.where('(start_date >= :start AND start_date <= :end) OR (end_date >= :start AND end_date <= :end)', params)
.exists?
end
private
def must_not_be_intersected
errors.add :base, 'Other task running on the same period' if intersected?
end
end

How do I search for a date field after or before a certain date in Active Record

I know I can use a range to search where a date lies between 2 dates. For example:
User.where(:created_at => start_date..end_date )
But how would I do an open ended search for all dates before or after a date?
Thanks for any help
You can simply to this :
User.where("created_at >= ?", start_date )
Or this
User.where("created_at <= ?", end_date )

Comparing Time.now with model dates

my Project model has 2 datetime atttributes: start_date and end_date.
Now I want all projects where the current time is in between these dates.
I tried something like this with the start_date to start with:
#projects = Project.where(:start_date <= Time.now)
But this returns an error:
comparison of Symbol with Time failed
Any ideas? Thanks!
Unlike some ORMs, active record doesn't augment the symbol class with methods to allow expressions other than equality to be expressed in this way. You just have to do
Project.where('start_date <= ?', Time.now)
The squeal gem adds this sort of stuff and allows you to write
Project.where{start_date < Time.now}
You can't do this: :start_date <= Time.now. You're comparing a symbol and a date with the <= operator.
If you want to add a condition to your query, pass it as a string:
Project.where("start_date <= ?", Time.now);
Unfortunately, with a where clause comparing dates, you'll have to drop into SQL. Try something like this instead:
#projects = Project.where(['projects.start_date <= ?', Time.now])

RoR | Range of Dates not traversing multiple months

I'm trying to create an array of dates for a calendar where there are a few extra day for the next and previous month that will fill in the week.
Here is my current method to try and get the array
def calendar
selected_month = Date.civil((Time.zone.now.year).to_i, (Time.zone.now.month).to_i)
start_date = selected_month.beginning_of_month
start_date.sunday? ? start_date : start_date.beginning_of_week.advance(:days => -1)
end_date = selected_month.end_of_month
end_date.sunday? ? end_date.advance(:days => 1).end_of_week : end_date
#only puts 1-30/31 and does not include the extra off set of days from start and end. :(
date_range = (start_date..end_date).to_a
end
The problem is the rang only start at 1 and goes to the end of the month even though the start and end days exceed that.
I'm not married to this way of getting the array so maybe you have a better whole idea?
You forgot to reassign the values of start_date and end_date.
start_date = selected_month.beginning_of_month
start_date = start_date.sunday? ? start_date : start_date.beginning_of_week.advance(:days => -1)
end_date = selected_month.end_of_month
end_date = end_date.sunday? ? end_date.advance(:days => 1).end_of_week : end_date

Selecting table entries where a given date is between the :start date and :end date

I have an object that has a start date and an end date, in order to represent the time that the object is valid.
Given a date, is there a way to only select those objects that have valid ranges that contain the date?
I tried fiddling with between, but couldn't get the syntax right.
Thanks!
This is often implemented using a named scope that does the appropriate restriction that identifies which records are visible at the current point in time:
class MyRecord < ActiveRecord::Base
named_scope :visible,
:conditions => 'visible_from<=UTC_TIMESTAMP() AND visible_to>=UTC_TIMESTAMP'
end
This can be altered to use place-holders for more arbitrary dates:
class MyRecord < ActiveRecord::Base
named_scope :visible_at, lambda { |date| {
:conditions => [
'visible_from<=? AND visible_to>=?',
date, date
]
}}
end
Presumably your dates are stored as UTC, as it is a considerable nuisance to convert from one local-time to another for the purposes of display.
You can select all visible models like this:
#records = MyRecord.visible.all
#records = MyRecord.visible_at(2.weeks.from_now)
If you were doing this for "given_date".
select *
from table
where start_date <= given_date
and end_date >= given_date
This is how you'd do it using active record.
Foo.find(:all, :conditions => ['valid_from <= ? and valid_to >= ?', valid_date, valid_date])

Resources