I'm trying to figure out the most efficient way to find the closest payday from a given date.
Let's say we know payday are every 14 days and that January 6, 2022 was one of them. What is the most efficient way to find the next payday for a given date (the date is the beginning of a week actually) from a known payday?
Here is a current working ugly implementation
def payday_first_date
# TODO: Very reliable, but very inefficient
@payday_first_date ||= begin
date = known_pay_day
date -= 14.days until date < given_date
date = 14.days until date > given_date
date
end
end
def known_pay_day
# Thursday January 6, 2022 was a payday
@known_pay_day ||= Date.new(2022, 2, 17)
end
The given_date could be in the future and also in the past. It can be a date from another year aswell.
Thanks in advance!
CodePudding user response:
First define the known pay date and two helper methods.
require 'date'
def date_str_to_date_obj(date_str)
DateTime.strptime(date_str, "%B %d, %Y").to_date
end
known_date = date_str_to_date_obj("January 6, 2022")
#=> #<Date: 2022-01-06 ((2459586j,0s,0n), 0s,2299161j)>
For presentation only:
def date_obj_to_date_str(date_obj)
date_obj.strftime("%B %d, %Y, %A")
end
date_obj_to_date_str(known_date)
#=> "January 06, 2022, Thursday"
The main method follows.
def closest_pay_day(known_date, target_date)
nbr_pay_dates = (target_date - known_date)/14.0
last_pay_date = known_date nbr_pay_dates.floor * 14
next_pay_date = last_pay_date 14
(next_pay_date - target_date < target_date - last_pay_date) ?
next_pay_date : last_pay_date
end
Suppose the target date is after the known pay date.
target_date_str = "March 26, 2022"
Then
target_date = date_str_to_date_obj(target_date_str)
#=> #<Date: 2022-03-26 ((2459665j,0s,0n), 0s,2299161j)>
date_obj_to_date_str(target_date)
#=> "March 26, 2022, Saturday"
The closest pay period to the target date is therefore
closest = closest_pay_day(known_date, target_date)
#=> #<Date: 2022-03-31 ((2459670j,0s,0n), 0s,2299161j)>
date_obj_to_date_str(closest)
#=> "March 31, 2022, Thursday"
which is
(target_date- closest).to_i
#=> -5
days before the target date, meaning 5 days after the target date.
Now suppose the target date is before the known pay date.
target_date_str = "October 19, 2021"
Then
target_date = date_str_to_date_obj(target_date_str)
#=> #<Date: 2021-10-19 ((2459507j,0s,0n), 0s,2299161j)>
date_obj_to_date_str(target_date)
#=> "October 19, 2021, Tuesday"
date_obj_to_date_str(closest_pay_day(known_date, target_date))
#=> "October 14, 2021, Thursday"
