Donato
Donato

Reputation: 2777

find start and end of range given a point

I created this basic class right here:

class TimePeriod
  MONTHS_PER_QUARTER = 3
  QUARTER_RANGE = {
    0 => [1,3],
    1 => [4,6],
    2 => [7,9],
    3 => [10,12]
  }

  def self.quarter(month_num)
    (month_num - 1) / MONTHS_PER_QUARTER
  end

  def self.quarter_range(month_num)
    quarter = quarter month_num
    t1,t2 = QUARTER_RANGE[quarter]
    [Time.parse(Date::MONTHNAMES[t1]).beginning_of_month, Time.parse(Date::MONTHNAMES[t2]).end_of_month]
  end
end 

It gives me a time range for a quarter, given a month provided as an integer:

> TimeUtils.quarter_range(Time.now.month)
 => [2015-04-01 00:00:00 -0400, 2015-06-30 23:59:59 -0400] 

So it works. However, I have cheated. I had difficulty finding the start and end, given, let's say, the month 6. So I hardcoded the values in the QUARTER_RANGE constant. I want to be able to remove that QUARTER_RANGE constant and find the beginning and end (e.g. [4,6]) without it.

So for example, if the input 3 (March),6 (June),9(September),12(December) is passed, I will know its the end of the quarter, using modulus arithmetic:

3 % 3
=> 0
6 % 3
=> 0
9 % 3
=> 0
12 % 3
=> 0 

But the tricky part is given let's say 5 (May), how can I return [4,6]?

Upvotes: 0

Views: 66

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110685

You could do the following:

MONTHS_PER_PERIOD = 3
PERIODS = (1..12).step(MONTHS_PER_PERIOD).map do |m|
   m..(m+MONTHS_PER_PERIOD-1)
end
  #=> [1..3, 4..6, 7..9, 10..12]

def month_to_period(m)
  PERIODS.find { |p| p.cover?(m) }
end

(1..12).each { |m| puts month_to_period(m) }
1..3
1..3
1..3
4..6
4..6
4..6
7..9
7..9
7..9
10..12
10..12
10..12

MONTHS_PER_PERIOD = 2
PERIODS = (1..12).step(MONTHS_PER_PERIOD).map do |m|
   m..(m+MONTHS_PER_PERIOD-1)
end
  #=> [1..2, 3..4, 5..6, 7..8, 9..10, 11..12] 

(1..12).each { |m| puts month_to_period(m) }
1..2
1..2
3..4
3..4
5..6
5..6
7..8
7..8
9..10
9..10
11..12
11..12

Upvotes: 0

steenslag
steenslag

Reputation: 80065

(1..12).each do |m|
  low = 3*((m-1)/3) + 1
  p m, [low, low+2]
end

result:

1
[1, 3]
2
[1, 3]
3
[1, 3]
4
[4, 6]
5
[4, 6]
6
...

Upvotes: 1

MCBama
MCBama

Reputation: 1490

Well, I'm not sure why you want it but if you want to use modulo this should work out how you want:

month = some_num
quarter_range = []
if month%3 == 0
  # end of quarter
  quarter_range = [month-2, month]
elsif month%3 == 1
  # beginning of quarter
  quarter_range = [month, month+2]
else
  # middle of quarter
  quarter_range = [month-1, month+1]
end

return quarter_range

Upvotes: 0

Jordan Running
Jordan Running

Reputation: 106027

You can get the start of the quarter like this:

def qtr_start(mon)
  mon - (mon - 1) % MONTHS_PER_QUARTER
end

qtr_start(9) # => 7

The end of the quarter is just that plus two:

def qtr_end(mon)
  qtr_start(mon) + 2
end

qtr_end(9) # => 9

Put them together:

def qtr_start_end(mon)
  start = mon - (mon - 1) % MONTHS_PER_QUARTER
  [ start, start + 2 ]
end

(1..12).each do |mon|
  start_end = qtr_start_end(mon)
  puts "Month #{mon} is in quarter #{start_end.inspect}"
end

# => Month 1 is in quarter [1, 3]
#    Month 2 is in quarter [1, 3]
#    Month 3 is in quarter [1, 3]
#    Month 4 is in quarter [4, 6]
#    Month 5 is in quarter [4, 6]
#    Month 6 is in quarter [4, 6]
#    Month 7 is in quarter [7, 9]
#    Month 8 is in quarter [7, 9]
#    Month 9 is in quarter [7, 9]
#    Month 10 is in quarter [10, 12]
#    Month 11 is in quarter [10, 12]
#    Month 12 is in quarter [10, 12]

Upvotes: 1

Related Questions