user3007294
user3007294

Reputation: 951

Getting middle and end of the month dates in Ruby

I am trying to write a payroll program and one of the payment methods is twice a month (the 15th and 30th and/or 31st). I am able to get the payment dates for the current month, but I need to get them printed for the following year. My code thus far is:

require "active_support/core_ext"
require 'date'

def twice_a_month_payment_schedule
  middle_of_month = Date.today.at_end_of_month - 15
  end_of_month = Date.today.at_end_of_month
  one_year = Date.today.at_end_of_month + 365
  starting_payment_date = Date.parse(start_date) ### start_date is an argument in the format of "%Y-%m-%d".

  while starting_payment_date < one_year
    if middle_of_month.saturday?
      middle_of_month - 1
    elsif middle_of_month.sunday?
      middle_of_month - 2
    elsif end_of_month.saturday?
      end_of_month - 1
    elsif end_of_month.sunday?
      end_of_month - 2
    end
    starting_payment_date += 1
  end
  pay_dates << middle_of_month.strftime("%m-%d-%Y")
  pay_dates << end_of_month.strftime("%m-%d-%Y")
  pay_dates
end

Any advice would be appreciated!

Thanks

Upvotes: 1

Views: 1396

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

This is a comment, not an answer. I wanted to point out a small problem with your code and also suggest how you can organize it a little better. I've taken @Nick's code and made a few changes.

I understand you do not want paydays to fall on weekends. Therefore, instead of:

if middle_of_month.saturday?
  middle_of_month - 1
elsif middle_of_month.sunday?
  middle_of_month - 2
elsif end_of_month.saturday?
  end_of_month - 1
elsif end_of_month.sunday?
  end_of_month - 2
end

you want:

if middle_of_month.saturday?
  middle_of_month - 1
elsif middle_of_month.sunday?
  middle_of_month - 2
end

if end_of_month.saturday?
  end_of_month - 1
elsif end_of_month.sunday?
  end_of_month - 2
end

As it stands, if both paydays initially fall on a weekend, only the mid-month payday will be changed. With this modification, the operations for each payday are nearly the same, so it makes sense to eliminate the repetitive bits. Here's how you might do it:

require "active_support/core_ext"
require 'date'

def twice_a_month_payment_schedule(year, month)
  base = Date.new(year, month)
  [check_and_format_payday(base+14),
   check_and_format_payday(base.at_end_of_month)]
end

def check_and_format_payday(payday)
  case
  when payday.saturday?
    payday -= 1
  when payday.sunday?
    payday -= 2
  end
  payday.strftime("%a %m-%d-%Y")
end

puts "Jan 2014: #{twice_a_month_payment_schedule(2014, 1)}"
#  Jan 2014: ["Wed 01-15-2014", "Fri 01-31-2014"]
"Feb 2014: #{twice_a_month_payment_schedule(2014, 2)}"
#  Feb 2014: ["Fri 02-14-2014", "Fri 02-28-2014"]
"Mar 2014: #{twice_a_month_payment_schedule(2014, 3)}"
#  Mar 2014: ["Fri 03-14-2014", "Mon 03-31-2014"]
puts "Aug 2014: #{twice_a_month_payment_schedule(2014, 8)}"
#  Aug 2014: ["Fri 08-15-2014", "Fri 08-29-2014"]
puts "May 2015: #{twice_a_month_payment_schedule(2015, 5)}"
#  May 2015: ["Fri 05-15-2015", "Fri 05-29-2015"]
puts "Feb 2024: #{twice_a_month_payment_schedule(2024, 2)}"
#  Feb 2024: ["Thu 02-15-2024", "Thu 02-29-2024"]
puts "Dec 2135: #{twice_a_month_payment_schedule(2135, 12)}"
#  Dec 2135: ["Thu 12-15-2135", "Fri 12-30-2135"]

Notice that I changed the output format slightly to include the day-of-week.

require "active_support/core_ext"

is only needed for the method at_end_of_month. You could alternatively define it yourself:

class Date
  def at_end_of_month
   next_month - 1
  end
end

Upvotes: 1

Nick Veys
Nick Veys

Reputation: 23939

Why not generalize the helper to get the dates for any year/month:

require "active_support/core_ext"
require 'date'

def twice_a_month_payment_schedule(year, month)
  base = Date.new(year, month)
  middle_of_month = 14.days.since(base)
  end_of_month = base.at_end_of_month

  if middle_of_month.saturday?
    middle_of_month - 1
  elsif middle_of_month.sunday?
    middle_of_month - 2
  elsif end_of_month.saturday?
    end_of_month - 1
  elsif end_of_month.sunday?
    end_of_month - 2
  end

  [middle_of_month.strftime("%m-%d-%Y"), end_of_month.strftime("%m-%d-%Y")]
end

puts "Jan 2014: #{twice_a_month_payment_schedule(2014, 1)}"
puts "Mar 2014: #{twice_a_month_payment_schedule(2014, 3)}"
puts "Aug 2014: #{twice_a_month_payment_schedule(2014, 8)}"
puts "May 2015: #{twice_a_month_payment_schedule(2015, 5)}"
puts "Feb 2024: #{twice_a_month_payment_schedule(2024, 2)}"
puts "Dec 2135: #{twice_a_month_payment_schedule(2135, 12)}"

Results:

⚡️ ruby derp.rb 
Jan 2014: ["01-15-2014", "01-31-2014"]
Mar 2014: ["03-15-2014", "03-31-2014"]
Aug 2014: ["08-15-2014", "08-31-2014"]
May 2015: ["05-15-2015", "05-31-2015"]
Feb 2024: ["02-15-2024", "02-29-2024"]
Dec 2135: ["12-15-2135", "12-31-2135"]

Upvotes: 2

Related Questions