How can I use only the month and day of Date.today in Rails? - ruby-on-rails

I want to display recent and upcoming anniversaries. Since dates are stored with year, the following code displays an empty array because none of my folks were married this year:
ann=Anniversary.where(anniversary: Date.today-7..Date.today+7)
So, how can I remove the year delimiter?

You can utilize the SQL EXTRACT method for this like below:
anniversaries = Anniversary.where('EXTRACT(month from anniversary) = ? AND EXTRACT(day from anniversary) IN (?)', Date.today.month, Date.today.day..(Date.today.day + 7))

Related

How to run Rails queries over multiple date ranges (weeks)

I'm trying to iterate over each week in the calendar year and run a query.
range = Date.new(2020,3,16)..Date.new(2020,3,22)
u = User.where(created_at: range).count
But I'd like to do this for EACH week in another range (say since the beginning of this year).
Ruby's Date has a cweek function that gives you the week number but there doesn't seem to be a way to easily get from the week number to the date range.
Anyway, not sure how helpful cweek will be as I need week to run Sunday -> Saturday.
Thoughts?
I'm assuming this is Postgres and the model name is User based on your previous question.
If this blog is to to believed you can shift a date one day to get sun-sat day week.
User.group("(date_trunc('week', created_at::date + 1)::date - 1)")
.count
If you want the to select the actual week number while you are at it you can select raw data from the database instead of using ActiveRecord::Calculations#count which is pretty limited.
class User
# #return [ActiveRecord::Result]
# the raw query results with the columns count, year, week
def self.count_by_biblical_week
connection.select_all(
select(
"count(*) as count",
"date_part('year', created_at)::integer as year",
"(date_part('week', created_at::date + 1) - 1)::integer as week"
).group(:week, :year)
)
end
end
Usage:
results = User.where(created_at: Date.new(2020,3,16)..Date.new(2020,3,22))
.count_by_biblical_week
results.each do |row|
puts [row[:year], row[:week], row[:count]].join(' | ')
end
Adding the year to the group avoids ambiguity if the results span multiple years.

Rails where statement with datetime.month

I am trying to find the data points within a database (PG) whose date is within a certain month (and would also quite like to check the year is the same also)
I have tried:
my_data.where("date.month = ?", month )
where 'month' is an integer (eg from Time.new.month) but doesn't seem to work...
So the query will be like this:
my_data.where("EXTRACT(MONTH FROM date) = ?", month)

Earliest date after current date without associated record

I have a Rails model DailyAssignment with a date column, and would like to find the first date after today which does not have a DailyAssignment associated with it.
For instance, if I have an instance today, no instance tomorrow, and an instance the day after tomorrow, this method should return tomorrow.
If I were to do this in Ruby, it would be something like:
(Date.today..1.year.since.to_date).find do |date|
DailyAssignment.where(date: date).empty?
end
This is medium okay since it will terminate the iteration once it finds a record, but has two issues:
Iterating through a collection in Ruby is slow.
Barring some sort of while construct, I need to specify an 'end' date.
Is there a nice, efficient way to do this in PostgreSQL?
If you can, you should use a custom query to search through your database (these kind of searches are a lot faster within the DB).
If you search for a date within a time range, you can use the
generate_series(timestamp, timestamp, interval) function:
select s
from generate_series(?, ? + interval '1 year'), interval '1 day') s
left join daily_assignment on s = "date"
where "date" is null
limit 1
If you have no real upper bound, you can use a self-join to get the next free date:
select coalesce(
(select c."date" + interval '1 day'
from daily_assignment c
left join daily_assignment n on n."date" = c."date" + interval '1 day'
where c."date" > ? - interval '1 day'
and n."date" is null
order by c."date"
limit 1),
? + interval '1 day'
)
? marks mean the parameter of today (you may need casts, depending on your input); you could use now() instead, if you prefer.
P.S.: please, do not use date as a column name, it is a reserved word in SQL, and tells nothing about the column itself. Instead, you can use names like created_at, updated_at, happens_at, etc. or even at_date.
What I propose is to do 1 select query between dates, then loop your results and compare them with your selected results.
# select all dailyassignments
results = DailyAssignment.where("date >= from_date AND date <= to_date")
not_found_dates = []
(Date.today..1.year.since).find do |date|
found_assignment = results.detect {|instance| instance.date == date }
not_found_dates << date if found_assignment.nil?
end
You can try it this way:
def first_date_without_assignment
assignments = DailyAssignment.select('date').where('date > ?', Date.today)
return Date.tomorrow if assignments.empty?
assignment_dates = assignments.map(&:date)
date_range = (Date.tomorrow..(assignment_dates.last.advance(days: 1)).to_a
(date_range - assignment_dates).first
end
I didn't test it so I could mistype something, but it could work. I also find this, it should work on postgres http://www.postgresql.org/message-id/4F96EC90.6070600#encs.concordia.ca but it could be quite hard to write in rails or at least bad looking.

How to select data by monthly and weekly and quarterly

I have the an Order model in the following
If today is 5/3
and I want to sum the previous 3 months data of order, how to do it ?
I mean I want to show the 2/1 ~ 4/30 excluding the orders in May.
If today is 2014/4/20, and I want to show the sum of previous 3 weeks data. 2014/2/1~2/15
How to do it in Rubic way ?
You want something along the lines:
date = DateTime.now.utc
Order.where('created_at >= ? and created_at <= ?', date.beginning_of_month, date.utc.end_of_month).sum('price')
Where price is the column you want to sum.
You can reuse the logic of #Santosh in order to get the dates you want =)
start_date = 3.months.ago.beginning_of_month
end_date = 1.month.ago.end_of_month
You can write your query based on these dates. Same logic can be applied for weeks also.

Comparing datetime and date in a .where() on Rails

I'm working on an event system where admins can select events to feature and add promotional text. As they need to add additional text the featured events are in their own table and reference the event details.
I'm now trying to output featured events for each day in the next week. Simplified example:
day = DateTime.now.to_date
featured_events = #featured_events.where('event.start_datetime = ?', day)
The problem is that start_datetime is in datetime format and day is in date format so it always outputs nothing. Is it possible to compare these two values with .where()?
Thanks!
May be you're looking for this:
#featured_events.where('event.start_datetime > ? and event.start_datetime < ?', DateTime.now, 1.day.from_now.beginning_of_day)
You don't say what database you're using.
In PostgreSQL we'd truncate the datetime inside the DB query so the DBM can do the compare. On MySQL we'd use a function to convert the datetime to a date.

Resources