Class: WorkingCalendar

Inherits:
Object
  • Object
show all
Defined in:
lib/almirah/project/working_calendar.rb

Overview

Projects the working-day planning axis (ADR-198 / ADR-195) onto real calendar dates (ADR-205). Working day 1 is the first working date on or after the anchor; Saturdays, Sundays, and any configured holiday are non-working — skipped when counting working days, but still occupying calendar columns. This is a pure projection: it never changes the schedule, the chain, or the buffer.

Constant Summary collapse

SATURDAY =
6
SUNDAY =
0
FRIDAY =
5

Instance Method Summary collapse

Constructor Details

#initialize(anchor: Date.today, holidays: []) ⇒ WorkingCalendar

Returns a new instance of WorkingCalendar.



16
17
18
19
# File 'lib/almirah/project/working_calendar.rb', line 16

def initialize(anchor: Date.today, holidays: [])
  @holidays = holidays.to_set
  @start = first_working_on_or_after(anchor)
end

Instance Method Details

#business_axis(count) ⇒ Object

The first count business-day (weekday) dates from the anchor, holidays included and weekends excluded — the calendar labels for an axis of count columns, even when it runs past the schedule to cover authored actuals (ADR-213). Empty for a count below 1.



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/almirah/project/working_calendar.rb', line 67

def business_axis(count)
  return [] if count < 1

  dates = []
  date = @start
  while dates.length < count
    dates << date unless weekend?(date)
    date += 1
  end
  dates
end

#business_column_for(date) ⇒ Object

The 0-based business-column index of a real calendar date relative to the anchor (ADR-213): the count of weekdays from the anchor through the date, minus one. A weekend date snaps to the preceding weekday's column; a date on or before the anchor clamps to column 0. Used to place authored committed/logged dates on the same business-day axis as the schedule.



84
85
86
87
88
# File 'lib/almirah/project/working_calendar.rb', line 84

def business_column_for(date)
  return 0 if date <= @start

  (@start..date).count { |d| !weekend?(d) } - 1
end

#business_columns(working_day_count) ⇒ Object

The compact business-day axis (ADR-206): weekday dates from working day 1 through the working_day_count-th working day, excluding Saturdays and Sundays but including weekday holidays. Empty for a count below 1.



51
52
53
54
55
# File 'lib/almirah/project/working_calendar.rb', line 51

def business_columns(working_day_count)
  return [] if working_day_count < 1

  (@start..date_for(working_day_count)).reject { |date| weekend?(date) }
end

#business_index(working_day) ⇒ Object

The 0-based business-column index of the n-th working day: the count of weekdays (holidays included, weekends excluded) from the anchor through it.



59
60
61
# File 'lib/almirah/project/working_calendar.rb', line 59

def business_index(working_day)
  (@start..date_for(working_day)).count { |date| !weekend?(date) } - 1
end

#column_index(working_day) ⇒ Object

The 0-based calendar column index of the n-th working day within columns.



44
45
46
# File 'lib/almirah/project/working_calendar.rb', line 44

def column_index(working_day)
  (date_for(working_day) - @start).to_i
end

#columns(working_day_count) ⇒ Object

Every calendar date from working day 1 through the working_day_count-th working day inclusive, including the non-working dates in between. Empty for a count below 1.



37
38
39
40
41
# File 'lib/almirah/project/working_calendar.rb', line 37

def columns(working_day_count)
  return [] if working_day_count < 1

  (@start..date_for(working_day_count)).to_a
end

#date_for(working_day) ⇒ Object

The calendar date of the n-th working day (1-based) counted from the anchor.



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/almirah/project/working_calendar.rb', line 22

def date_for(working_day)
  return @start if working_day <= 1

  date = @start
  remaining = working_day - 1
  while remaining.positive?
    date += 1
    remaining -= 1 if working?(date)
  end
  date
end

#friday?(date) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/almirah/project/working_calendar.rb', line 90

def friday?(date)
  date.wday == FRIDAY
end

#non_working?(date) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/almirah/project/working_calendar.rb', line 98

def non_working?(date)
  weekend?(date) || @holidays.include?(date)
end

#weekend?(date) ⇒ Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/almirah/project/working_calendar.rb', line 102

def weekend?(date)
  [SATURDAY, SUNDAY].include?(date.wday)
end

#working?(date) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/almirah/project/working_calendar.rb', line 94

def working?(date)
  !non_working?(date)
end