Class: BusinessDaysSingleton

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/business-days.rb

Instance Method Summary collapse

Constructor Details

#initializeBusinessDaysSingleton

Returns a new instance of BusinessDaysSingleton.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/business-days.rb', line 8

def initialize
  @holidays = []

  # Setup holidays in an interval of 3 years
  from = Time.current.year - 1
  to = Time.current.year + 2

  # 1. Get all holidays in given years interval from Holidays gem
  Holidays.between(Date.civil(from, 1, 1), Date.civil(to, 12, 31), :br, :informal).each do |holiday|
    # Include holiday
    @holidays.push(holiday[:date])

    # 2. If Carnaval, include the day before it (it's a bank holiday)
    if holiday[:name] == "Carnaval"
      @holidays.push(holiday[:date] - 1.day)
    end
  end

  # 3. Add the latest business day in each year (it's a bank holiday)
  # (from..to).each do |year|
  #   @holidays.push(latest_non_bank_business_day(year))
  # end
end

Instance Method Details

#add_holiday(date) ⇒ Object

Consider the given date as a non-business day for all commands after this.

Parameters:

  • date (Date)

    the non-business date to be add.

Raises:

  • (ArgumentError)


92
93
94
95
96
# File 'lib/business-days.rb', line 92

def add_holiday(date)
  raise ArgumentError.new('Not a date') unless date.kind_of?(Date)

  @holidays.push(date)
end

#business_day?(date) ⇒ Boolean

Check if the given date is a business day

Parameters:

  • date (Date)

    the non-business date to be add.

Returns:

  • (Boolean)

    true if the given date is a business day, false otherwise.

Raises:

  • (ArgumentError)


82
83
84
85
86
87
# File 'lib/business-days.rb', line 82

def business_day?(date)
  raise ArgumentError.new('Not a date') unless date.kind_of?(Date)

  weekend = [6, 7].include?(date.cwday)
  !(weekend || @holidays.include?(date))
end

#business_days(from, to) ⇒ Integer

Returns number of business days between the two dates.

Returns:

  • (Integer)

    number of business days between the two dates

Raises:

  • (ArgumentError)


65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/business-days.rb', line 65

def business_days(from, to)
  raise ArgumentError.new('Not a date: from') unless from.kind_of?(Date)
  raise ArgumentError.new('Not a date: to') unless to.kind_of?(Date)
  count = 0

  while  from <= to
    count +=1 if self.business_day?(from)
    from = from + 1.day
  end

  count
end

#business_days_from_utc_time(days, time) ⇒ Time

Compute the date obtained by adding the given amount of business days to the given time.

Parameters:

  • days (Integer)

    how many business days to add to given time.

  • time (Time)

    the start time in UTC from which the business days will be added.

Returns:

  • (Time)

    the computed business day in UTC time (at midnight in Brasilia time)



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/business-days.rb', line 37

def business_days_from_utc_time(days, time)
  # Get offset from reference data (based on Brasilia timezone)
  offset = time.in_time_zone('Brasilia').formatted_offset()

  # Get date from time in reference offset
  date = (time + offset.to_i.hours).to_date

  # Add days until we reach the specified business days
  count = 0
  while count < days
    time += 24*60*60

    offset = time.in_time_zone('Brasilia').formatted_offset()
    date = (time + offset.to_i.hours).to_date
    if business_day?(date)
      count +=1
    end
  end

  (date.to_time.utc.midnight - offset.to_i.hours)
end

#next(date) ⇒ Date

Returns the first business day after the given date.

Parameters:

  • date (Date)

    the reference date.

Returns:

  • (Date)

    the first business day after the reference date.

Raises:

  • (ArgumentError)


120
121
122
123
124
125
126
127
128
129
# File 'lib/business-days.rb', line 120

def next(date)
  raise ArgumentError.new('Not a date') unless date.kind_of?(Date)

  date = date + 1.days
  while !business_day?(date)
    date = date + 1.days
  end

  date
end

#previous(date) ⇒ Date

Returns the first business day before the given date.

Parameters:

  • date (Date)

    the reference date.

Returns:

  • (Date)

    the first business day before the reference date.

Raises:

  • (ArgumentError)


135
136
137
138
139
140
141
142
143
144
# File 'lib/business-days.rb', line 135

def previous(date)
  raise ArgumentError.new('Not a date') unless date.kind_of?(Date)

  date = date - 1.days
  while !business_day?(date)
    date = date - 1.days
  end

  date
end

#remove_holiday(date) ⇒ Object

Remove given date from holidays list for all commands after this.

Parameters:

  • date (Date)

    the non-holiday date to be add.

Raises:

  • (ArgumentError)


101
102
103
104
105
# File 'lib/business-days.rb', line 101

def remove_holiday(date)
  raise ArgumentError.new('Not a date') unless date.kind_of?(Date)

  @holidays.delete(date)
end

#remove_latest_non_bank_business_daysObject

Remove latest holiday for each year



108
109
110
111
112
113
114
# File 'lib/business-days.rb', line 108

def remove_latest_non_bank_business_days
  years = Set.new(@holidays.map { |d| d.year })
  years.each do |year|
    max_date = @holidays.select { |d| d.year == year }.max
    self.remove_holiday(max_date) if max_date.strftime('%m%d') >= "1229"
  end
end