class BusinessDateCalculator::Calendar

Public Class Methods

new(start_date, end_date, holidays) click to toggle source

Constroi a estrutura de dados a partir de uma lista de holidays que sao os feriados, e usando um periodo especificado (fechado nas duas pontas).

# File lib/business_date_calculator/calendar.rb, line 6
def initialize(start_date, end_date, holidays)
  build(start_date, end_date, holidays)
end

Public Instance Methods

adjust(date, convention) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 28
def adjust(date, convention)
  range_check(date)
  if not is_holiday?(date)
    date
  elsif convention == :unadjusted
    date
  else
    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) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 45
def advance(date, n, convention = :following, margin = 30)
  date = date.to_date
  range_check(date)
  index = adjusted_date_index(date, convention) + n
  if index < 0
    build(date + (index - margin).days, @end_date, @holidays)
    return advance(date, n, convention, margin + 30)
  end
  @business_dates[adjusted_date_index(date, convention) + n]
end
is_holiday?(date) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 10
def is_holiday?(date)
  date.wday == 0 || date.wday == 6 || @holidays.include?(date)
end
last_day_of_previous_month(date) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 56
def last_day_of_previous_month(date)
  m = date.month
  y = date.year
  if m == 1
    m = 0
    y = y - 1
  end
  adjust(Date.civil(y, (m - 1), -1), :preceding)
end
networkdays(date1, date2, convention1 = :unadjusted, convention2 = :unadjusted) click to toggle source

Retorna o numero de dias uteis entre as duas data especificadas, inclusive. As duas datas devem ser dias uteis, ou caso não seja, deve ser especificado uma convenção de ajuste para cada data. A primeira data deve ser menor ou igual a segunda.

# File lib/business_date_calculator/calendar.rb, line 18
def networkdays(date1, date2, convention1 = :unadjusted, convention2 = :unadjusted)
  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

Protected Instance Methods

adjusted_date_index(date, convention) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 113
def adjusted_date_index(date, convention)
  @business_date_index[adjust(date, convention)]
end
build(start_date, end_date, holidays) click to toggle source
# File lib/business_date_calculator/calendar.rb, line 68
def build(start_date, end_date, holidays)
  # garante que start_date e end_date sao dias uteis
  while start_date.wday == 0 || start_date.wday == 6 || holidays.include?(start_date) do
    start_date -= 1.days
  end
  while end_date.wday == 0 || start_date.wday == 6 || holidays.include?(end_date) do
    end_date += 1.days
  end
  
  @start_date = start_date
  @end_date = end_date
  @holidays = holidays
  @business_dates = []
  @business_date_index = {}
  @next_business_date_index = {}
  @prev_business_date_index = {}
  
  d = start_date
  i = 0
  while d <= end_date do
    if is_holiday?(d)
      # dia não útil, mapeia o indice do dia util anterior e proximo
      @next_business_date_index[d] = i
      @prev_business_date_index[d] = i - 1
    else
      # dia util, adiciona ao final do array, e mapeia o indice do array no mapa
      @business_dates << d
      @business_date_index[d] = i
      i = i + 1
    end
    d += 1.days
  end
end
range_check(date) click to toggle source

Verifica se a data passada esta entre o periodo desta instancia.

# File lib/business_date_calculator/calendar.rb, line 103
def range_check(date)
  if date < @start_date
    # puts "Reconstruindo calculadora de feriados pois dia #{date} eh menor que #{@start_date} -> #{@end_date}"
    build(date - 2.days, @end_date, @holidays)
  elsif date > @end_date
    # puts "Reconstruindo calculadora de feriados pois dia #{date} eh maior que #{end_date}"
    build(@start_date, date + 252.days, @holidays)
  end
end