How to get user's birthday based on day and month only - ruby-on-rails

I want to have a member list for today's birthday and upcoming birthday(tommorow).
In users.controller.rb
def birthday
#birthday_users = User.all.order("created_at DESC").where(:birthday => Date.today)
end
def upcoming_birthday
#upcoming_birthday_user = User.all.order("created_at DESC").where(:birthday => 1.days.from_now )
end
These codes work only when the day, month and year are the same as today.
Example:
User 1's birthday = October 3 2018 (Showing on the birthday list)
User 2's birthday = October 3 2000 (Not showing on the birthday list)

In User model
PostgreSql
scope :today_birthday, { where('EXTRACT(month FROM birthday) = ? AND EXTRACT(day FROM birthday) = ?', Date.today.month, Date.today.day).order("created_at DESC") }
scope :upcoming_birthday, { where('EXTRACT(month FROM birthday) = ? AND EXTRACT(day FROM birthday) = ?', 1.days.from_now.month, 1.days.from_now.day).order("created_at DESC") }
MySql
scope :today_birthday, { where('MONTH(birthday) = ? AND DAY(birthday) = ?', Date.today.month, Date.today.day).order("created_at DESC") }
scope :upcoming_birthday, { where('MONTH(birthday) = ? AND DAY(birthday) = ?', 1.days.from_now.month, 1.days.from_now.day).order("created_at DESC") }

I'm assuming you want to find all users having a birthday today. So, you might want to ignore year and only consider month and day while querying. The below code might help you with that:
def birthday
#birthday_users = User.where('EXTRACT(month FROM birthday) = ? AND EXTRACT(day FROM birthday) = ?', Date.today.strftime("%m"), Date.today.strftime("%d"))
end
def upcoming_birthday
tomorrow = Date.today + 1.day
#upcoming_birthday_users = User.where('EXTRACT(month FROM birthday) = ? AND EXTRACT(day FROM birthday) = ?', tomorrow.strftime("%m"), tomorrow.strftime("%d"))
end

Related

Rails AR Date Range Query - Daylight Saving - Overlap

I have a Rails 3 application, how would one avoid an overlap happening due to daylight saving?
My problem is that I am having a form that generate reports. Auditing an inconsistency I noticed that a bunch of transactions show up in the week ending in March 11th also show up in the Week starting on March 12th.
The problem boils down to some thing like this...
Time.zone.parse('2018-03-11').to_datetime.end_of_day.utc
=> Mon, 12 Mar 2018 07:59:59 +0000
Time.zone.parse('2018-03-12').to_datetime.beginning_of_day.utc
=> Mon, 12 Mar 2018 07:00:00 +0000
The 1 hour overlap above seem to be where my problem lies. When checking date ranges (see actual code below) how can I avoid this overlap.
Actual Code
Here is the actual code that resemble filtering by date.
scope :filter_date, lambda { |starts, ends, date, transaction_type = :transaction|
_scope = scoped
starts = Time.zone.parse(starts).to_datetime if starts.class == String and starts.present?
ends = Time.zone.parse(ends).to_datetime.tomorrow if ends.class == String and ends.present?
begin
case date
when 'settled'
transaction_type == "batch" ? date_field = 'deposited_at' : date_field = 'settled_at'
_scope = _scope.order('transactions.'+date_field+' DESC')
_scope = _scope.where("transactions."+date_field+" >= ?", starts) if starts.present?
_scope = _scope.where("transactions."+date_field+" < ?", ends) if ends.present?
else # created, nil, other
_scope = _scope.order('transactions.created_at DESC')
_scope = _scope.where("transactions.created_at >= ?", starts) if starts.present?
_scope = _scope.where("transactions.created_at < ?", ends) if ends.present?
end
end
_scope
}
Stack
Ruby 2.1
Rails 3.2
PG
Question
How can I overcome this overlap of time where the daylight saving takes effect.
Try this solution. I think it should solve your issue:
scope :filter_date, lambda { |starts, ends, date, transaction_type = :transaction|
_scope = scoped
if starts.class == String and starts.present?
starts = Time.zone.parse(starts)
starts += 1.hour if starts.dst?
starts = starts.to_datetime
end
if ends.class == String and ends.present?
ends = Time.zone.parse(ends) + 1.day
ends += 1.hour if ends.dst?
ends = ends.to_datetime
end
begin
case date
when 'settled'
transaction_type == "batch" ? date_field = 'deposited_at' : date_field = 'settled_at'
_scope = _scope.order('transactions.'+date_field+' DESC')
_scope = _scope.where("transactions."+date_field+" >= ?", starts) if starts.present?
_scope = _scope.where("transactions."+date_field+" < ?", ends) if ends.present?
else # created, nil, other
_scope = _scope.order('transactions.created_at DESC')
_scope = _scope.where("transactions.created_at >= ?", starts) if starts.present?
_scope = _scope.where("transactions.created_at < ?", ends) if ends.present?
end
end
_scope
}

Greater/Lower than works but equals doesn't on >= and <= on .where()

I have a Rails 4 app and I'm trying to make a simple search for my invoices with 3 optional arguments: Name of the client, Start Date, End Date.
The search works fine mostly, if I put a start date and an end date it works for < and >, but eventhough i used >= and <=, if the invoice date is the same to either start or end, it just won't show on the result list.
The tables used look like this:
Client Table
ID
Name
The rest of the fields aren't necessary
Invoice Table
ID
Client_ID
Total_Price
Created_At *only here for relevance*
My Invoice Controller Search method looks like this:
def search
if request.post?
#count = 0
#invoices = Invoice.all
if params[:start_date].present?
#invoices = Invoice.invoices_by_date(#invoices, params[:start_date], 'start')
if #invoices.present?
#count = 1
else
#count = 2
end
end
if params[:end_date].present?
#invoices = Invoice.invoices_by_date(#invoices, params[:end_date], 'end')
if #invoices.present?
#count = 1
else
#count = 2
end
end
if params[:name].present?
#invoices = Invoice.invoices_by_client(#invoices, params[:name])
if #invoices.present?
#count = 1
else
#count = 2
end
end
if #count == 2
flash.now[:danger] = "No results found."
#invoices = nil
end
#name = params[:name]
#start_date = params[:start_date]
#end_date = params[:end_date]
end
end
And the Invoice Model methods i use look like this:
def self.invoices_by_client(invoices, name)
invoices= invoices.includes(:client)
.select('invoices.created_at', 'invoices.total_price', 'clients.name')
.where("clients.name LIKE ?", "%#{name}%")
.references(:client)
return invoices
end
def self.invoices_by_date(invoices, date, modifier)
if modifier == 'start'
invoices = invoices.includes(:client)
.select('invoices.created_at', 'invoices.total_price', 'clients.name')
.where("invoices.created_at >= ?", date)
.references(:client)
elsif modifier == 'end'
invoices = invoices.includes(:client)
.select('invoices.created_at', 'invoices.total_price', 'clients.name')
.where("invoices.created_at <= ? ", date)
.references(:client)
end
return invoices
end
It probably isn't the best solution overall and I don't know if i did anything wrong so it would be great if you guys could help me with this.
I followed Alejandro's advice and messed around with the time aswell as the date, something like this:
if modifier == 'start'
invoices = invoices.includes(:client)
.select('invoices.created_at', 'invoices.total_price', 'clients.name')
.where("invoices.created_at >= ?", "#{date} 00:00:00") // Added the start time
.references(:client)
elsif modifier == 'end'
invoices = invoices.includes(:client)
.select('invoices.created_at', 'invoices.total_price', 'clients.name')
.where("invoices.created_at <= ? ", "#{date} 23:59:59") // Added end time aswell
.references(:client)
end
I forced the time for the start date as 00:00:00 and the time for the end date as 23:59:59 and it worked as desired. Thank you for the help man and i hope this helps other people!

Rails: How to loop through month?

I made a scope help me to select objects
scope :best_of_the_month, ->(year, month) do
time = Time.new(year, month)
start_time = time.beginning_of_month
end_time = time.end_of_month
where("created_at > ? AND created_at < ?", start_time, end_time).where("likes > ?", 15).where("rating > ?", 4.85).order_by_rating.to_a.uniq(&:author)
end
Then, I want to loop through this method, from 2014/1 to now. How can I do it?
Maybe something like this:
start_date = Date.create(2014,1).month
end_date = Date.today.month
#monthly_videos = []
(start_date..end_date).each do |year, month|
videos = Video.best_of_the_month(year, month)
#monthly_videos << videos
end
I find a solution here, How to Loop through Months in Ruby on Rails. But it seems about looping through the days. Not the month
With the best_of_the_month scope defined to take month and year as params, the following code should work:
date = Date.new(2014,1,1)
#monthly_videos = []
while true
videos = Video.best_of_the_month(date.year, date.month)
#monthly_videos << videos
date += 1.month
break if date == Date.today.beginning_of_month
end
You could use the Date#next_month method
date = Date.new(2014,1,1)
final_date = Date.new(Date.today.year, Date.today.month)
#monthly_video = []
loop do
#monthly_videos << Video.best_of_the_month(date.year, date.month)
break if date == final_date
date = date.next_month
end

How to create multiple records for each day in given quarter?

I have Shift model.
--- !ruby/object:Shift
attributes:
id:
starts_at:
ends_at:
I want to add singelton method to create shifts for each day in given quarter.
class Shift
def self.open_quarter(number, year)
starts_at = "08:00"
ends_at = "08:00"
...
end
end
How to implement that in best way? I want that each shifts starts_at 8.00 am and finish 8.00 am on next day.
def self.open_quarter(number, year)
start_time = Time.new(year, number*3 - 2, 1, 8)
while start_time.month <= number*3 && start_time.year == year
Shift.create{starts_at: start_time, ends_at: start_time += 24.hours}
end
end
make sure to set the correct timezone when using Time.new. Default is current timezone (see docs). You can also use Time.utc.
def self.open_quarter(number, year)
starts_at = "08:00 am"
ends_at = "08:00 pm"
quarter_start = Date.new(year, (number * 3)).beginning_of_quarter
quarter_end = Date.new(year, (number * 3)).end_of_quarter
(quarter_end - quarter_start).to_i.times do |n|
start_shift = "#{(quarter_start + n).to_s} #{starts_at}".to_datetime
end_shift = "#{(quarter_start + n).to_s} #{ends_at}".to_datetime
Shift.create(starts_at: start_shift, ends_at: end_shift)
end
end

Notification to others on birthday

I want to send notification mail to others whose birthday is not today.
I have used code to find out people having birthday today...
Code for controller:
#people = Person.find(:all, :conditions => ["DAY(date) = ? AND MONTH(date) = ?", Date.today.day, Date.today.month])
Now, how do I modify it to get people other than birthday person?
Surely it should be:
#people = Person.where('DAY(date) <> ? AND MONTH(date) <> ?', Date.today.day, Date.today.month)
Using OR it will exclude people from other months where the day is today and from other days of the current month.
#people = Person.where('DAY(date) <> ? OR MONTH(date) <> ?', Date.today.day, Date.today.month)
#people = Person.where("extract(month from date) != ? AND extract(day from date) != ?", Date.today.month, Date.today.day)

Resources