Class: BusinessDateCalculator::Calendar
- Inherits:
-
Object
- Object
- BusinessDateCalculator::Calendar
- Defined in:
- lib/business_date_calculator/calendar.rb
Overview
Calculadora de dias uteis com calendario customizavel de feriados.
Mantem uma estrutura de dados indexada cobrindo um intervalo de datas, expandida dinamicamente quando consultas saem do range inicial. Thread-safe (Monitor reentrante) e Marshal-friendly para uso com Rails.cache.
Marshal serialization collapse
-
#marshal_dump ⇒ Object
private
Monitor nao e serializavel via Marshal (Rails.cache usa Marshal).
- #marshal_load(data) ⇒ Object private
Instance Method Summary collapse
-
#adjust(date, convention) ⇒ Date
Ajusta uma data para o dia util mais proximo segundo a convencao indicada.
-
#advance(date, n, convention = :following, margin = 30) ⇒ Date
Avanca (ou recua)
ndias uteis a partir dedate. -
#initialize(start_date, end_date, holidays) ⇒ Calendar
constructor
Cria um novo calendario.
-
#is_holiday?(date) ⇒ Boolean
Verifica se uma data nao e util (fim de semana ou feriado).
-
#last_day_of_previous_month(date) ⇒ Date
Ultimo dia util do mes anterior ao da data passada.
-
#networkdays(date1, date2, convention1 = :unadjusted, convention2 = :unadjusted) ⇒ Integer
Conta dias uteis entre duas datas como “saltos” no indice de dias uteis.
Constructor Details
#initialize(start_date, end_date, holidays) ⇒ Calendar
Cria um novo calendario.
20 21 22 23 |
# File 'lib/business_date_calculator/calendar.rb', line 20 def initialize(start_date, end_date, holidays) @monitor = Monitor.new build(start_date, end_date, holidays) end |
Instance Method Details
#adjust(date, convention) ⇒ Date
Ajusta uma data para o dia util mais proximo segundo a convencao indicada. Se a data ja for util, retorna ela inalterada independente da convencao.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/business_date_calculator/calendar.rb', line 75 def adjust(date, convention) @monitor.synchronize do range_check(date) return date if !is_holiday?(date) || convention == :unadjusted case convention when :following @business_dates[@next_business_date_index[date]] when :preceding raise "Erro pegando data util anterior ao dia #{date}" if @prev_business_date_index[date].nil? @business_dates[@prev_business_date_index[date]] end end end |
#advance(date, n, convention = :following, margin = 30) ⇒ Date
Avanca (ou recua) n dias uteis a partir de date. Expande o calendario automaticamente quando n extrapola o range conhecido.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/business_date_calculator/calendar.rb', line 105 def advance(date, n, convention = :following, margin = 30) @monitor.synchronize do date = date.to_date range_check(date) index = adjusted_date_index(date, convention) + n if index.negative? # 2x folga sobre dias uteis cobre fins de semana e feriados em uma unica reconstrucao build(date + ((index * 2) - margin).days, @end_date, @holidays) return advance(date, n, convention, margin + 30) elsif index >= @business_dates.length overshoot = index - @business_dates.length + 1 build(@start_date, @end_date + ((overshoot * 2) + margin).days, @holidays) return advance(date, n, convention, margin + 30) end @business_dates[adjusted_date_index(date, convention) + n] end end |
#is_holiday?(date) ⇒ Boolean
Verifica se uma data nao e util (fim de semana ou feriado).
29 30 31 |
# File 'lib/business_date_calculator/calendar.rb', line 29 def is_holiday?(date) @monitor.synchronize { date.wday.zero? || date.wday == 6 || @holidays.include?(date) } end |
#last_day_of_previous_month(date) ⇒ Date
Ultimo dia util do mes anterior ao da data passada.
130 131 132 |
# File 'lib/business_date_calculator/calendar.rb', line 130 def last_day_of_previous_month(date) @monitor.synchronize { adjust(Date.civil(date.year, date.month, 1) - 1, :preceding) } end |
#marshal_dump ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Monitor nao e serializavel via Marshal (Rails.cache usa Marshal). Pula o monitor na serializacao e recria fresh na deserializacao.
139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/business_date_calculator/calendar.rb', line 139 def marshal_dump { start_date: @start_date, end_date: @end_date, holidays: @holidays, business_dates: @business_dates, business_date_index: @business_date_index, next_business_date_index: @next_business_date_index, prev_business_date_index: @prev_business_date_index } end |
#marshal_load(data) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
152 153 154 155 156 157 158 159 160 161 |
# File 'lib/business_date_calculator/calendar.rb', line 152 def marshal_load(data) @monitor = Monitor.new @start_date = data[:start_date] @end_date = data[:end_date] @holidays = data[:holidays] @business_dates = data[:business_dates] @business_date_index = data[:business_date_index] @next_business_date_index = data[:next_business_date_index] @prev_business_date_index = data[:prev_business_date_index] end |
#networkdays(date1, date2, convention1 = :unadjusted, convention2 = :unadjusted) ⇒ Integer
Conta dias uteis entre duas datas como “saltos” no indice de dias uteis. Equivalente a indice_util(date2) - indice_util(date1): mesma data retorna 0, segunda-feira ate sexta-feira da mesma semana retorna 4.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/business_date_calculator/calendar.rb', line 46 def networkdays(date1, date2, convention1 = :unadjusted, convention2 = :unadjusted) if date1 > date2 raise ArgumentError, "date1 must be less than or equal to date2 (got date1=#{date1}, date2=#{date2})" end @monitor.synchronize do range_check(date1) range_check(date2) i1 = adjusted_date_index(date1, convention1) i2 = adjusted_date_index(date2, convention2) raise "Adjusted date1 #{date1} is out of range" if i1.nil? raise "Adjusted date2 #{date2} is out of range" if i2.nil? i2 - i1 end end |