Class: Rupee::Calendar

Inherits:
Object
  • Object
show all
Extended by:
FindInstance
Defined in:
lib/rupee/calendar.rb,
lib/rupee/calendar/us.rb,
lib/rupee/calendar/japan.rb

Overview

An object representing a calendar, for use in determining the next payout date for a cash flow. Simple example:

require "rupee/calendar"

module Rupee
  class Calendar
    # It's recommended that you store your calendar inside the Calendar
    # class, as that way you'll have access to them as "constants." Also,
    # it gives you access to the month constants (JANUARY, FEBRUARY,
    # MARCH, etc.)
    MyCalendar = Rupee::Calendar.new("Sample calendar")

    # Weekends
    MyCalendar.has_weekends_off

    # Thanksgiving (fourth Thursday of November
      MyCalendar.has_day_off_on :thanksgiving do |date|
      date.month == NOVEMBER && date.thursday? && week_of(date) == 4
    end

    # Christmas (December 25 or nearest weekday)
    MyCalendar.has_day_off_on :christmas do |date|
      date.month == DECEMBER && nearest_weekday(date, 25)
    end

    # New Year's Day (January 1 or next weekday)
    MyCalendar.has_day_off_on :new_years do |date|
      date.month == JANUARY && next_weekday(date, 1)
    end
  end
end

# Christmas falls on a Sunday in 2011...
Rupee::Calendar::MyCalendar.day_off?(Time.new(2011, 12, 25))
# => true

# ... so we have the following Monday off...
Rupee::Calendar::MyCalendar.day_off?(Time.new(2011, 12, 26))
# => true

# ...then it's back to work
Rupee::Calendar::MyCalendar.day_off?(Time.new(2011, 12, 27))
# => false

You can also inherit from other calendars easily:

require "rupee/calendar"

class Rupee::Calendar
  # Pirates generally observe the Federal Reserve holiday schedule
  Blackbeard = US.copy

  # But they do observe Talk Like a Pirate Day
  Blackbeard.has_day_off_on :talk_like_a_pirate_day do |date|
    date.month == SEPTEMBER && date.day == 19
  end

  # And curse the Spanish Crown
  Blackbeard.remove_day_off_for :columbus_day
end

# Talk Like a Pirate Day
Rupee::Calendar::Blackbeard.day_off?(Time.new(2011, 9, 19))
# => true
Rupee::Calendar::US.day_off?(Time.new(2011, 9, 19))
# => false

# Columbus Day
Rupee::Calendar::Blackbeard.day_off?(Time.new(2011, 10, 10))
# => false
Rupee::Calendar::US.day_off?(Time.new(2011, 10, 10))
# => true

Constant Summary collapse

JANUARY =

A constant representing the month of January

1
FEBRUARY =

A constant representing the month of February

2
MARCH =

A constant representing the month of March

3
APRIL =

A constant representing the month of April

4
MAY =

A constant representing the month of May

5
JUNE =

A constant representing the month of June

6
JULY =

A constant representing the month of July

7
AUGUST =

A constant representing the month of August

8
SEPTEMBER =

A constant representing the month of September

9
OCTOBER =

A constant representing the month of October

10
NOVEMBER =

A constant representing the month of November

11
DECEMBER =

A constant representing the month of December

12
US =

The US Federal Reserve calendar

Calendar.new("The Federal Reserve Calendar")
Japan =

The national Japanese calendar

Calendar.new("The national Japanese calendar")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from FindInstance

find

Constructor Details

#initialize(description) ⇒ Calendar

Builds a calendar



112
113
114
115
# File 'lib/rupee/calendar.rb', line 112

def initialize(description)
  @description = description
  @days_off = {}
end

Instance Attribute Details

#days_offObject (readonly)

Functions used to determine whether a day is off



109
110
111
# File 'lib/rupee/calendar.rb', line 109

def days_off
  @days_off
end

#descriptionObject (readonly)

A description of the calendar



107
108
109
# File 'lib/rupee/calendar.rb', line 107

def description
  @description
end

Class Method Details

.last_week?(date) ⇒ Boolean

Whether the provided date falls in the last week of the month

Returns:

  • (Boolean)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/rupee/calendar.rb', line 184

def last_week?(date)
  case date.month
  when 9, 4, 6, 11
    # Thirty days hath September
    # April, June and November
    date.day > 23
  when 1, 3, 5, 7, 8, 10, 12
    # All the rest have thirty-one
    date.day > 24
  when 2
    # Save February, with twenty-eight days clear
    # And twenty-nine each leap year ;)
    date.day > (date.year % 4 == 0 && (date.year % 100 != 0 || date.year % 400 == 0)) ? 22 : 21
  end
end

.nearest_weekday(date, day) ⇒ Object

Calculates whether the provided date is the nearest weekday relative to the provided day of the month



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/rupee/calendar.rb', line 202

def nearest_weekday(date, day)
  case date.wday
  when 1     # Monday
    date.day.between?(day, day + 1)
  when 5     # Friday
    date.day.between?(day - 1, day)
  when 0, 6  # Weekends
    false
  else       # Tuesday - Thursday
    date.day == day
  end
end

.next_monday_if_sunday(date, day) ⇒ Object

Calculates whether the provided date is the day requested or, if the day requested falls on a Sunday, the following Monday



243
244
245
246
247
248
249
250
251
252
# File 'lib/rupee/calendar.rb', line 243

def next_monday_if_sunday(date, day)
  case date.wday
  when 1     # Monday
    date.day.between?(day, day + 1)
  when 0, 6  # Weekends
    false
  else       # Tuesday - Friday
    date.day == day
  end
end

.next_weekday(date, day) ⇒ Object

Calculates whether the provided date is the nearest weekday relative to the provided day of the month



217
218
219
220
221
222
223
224
225
226
# File 'lib/rupee/calendar.rb', line 217

def next_weekday(date, day)
  case date.wday
  when 1     # Monday
    date.day.between?(day, day + 2)
  when 0, 6  # Weekends
    false
  else       # Tuesday - Friday
    date.day == day
  end
end

.previous_weekday(date, day) ⇒ Object

Calculates whether the provided date is the nearest weekday relative to the provided day of the month



230
231
232
233
234
235
236
237
238
239
# File 'lib/rupee/calendar.rb', line 230

def previous_weekday(date, day)
  case date.wday
  when 5     # Friday
    date.day.between?(day - 2, day)
  when 0, 6  # Weekends
    false
  else       # Monday - Thursday
    date.day == day
  end
end

.week_of(date) ⇒ Object

Calculates the week of the month in which the given date falls



179
180
181
# File 'lib/rupee/calendar.rb', line 179

def week_of(date)
  (date.day - 1) / 7 + 1
end

Instance Method Details

#copyObject

Makes a copy of the calendar



118
119
120
121
122
123
124
125
126
# File 'lib/rupee/calendar.rb', line 118

def copy
  new_cal = Calendar.new @description.dup
  
  @days_off.each_pair do |key, day_off|
    new_cal.days_off[key] = day_off
  end

  new_cal
end

#day_off?(date) ⇒ Boolean

Returns true if the specified date is a holiday or day off

Returns:

  • (Boolean)


167
168
169
170
171
172
173
# File 'lib/rupee/calendar.rb', line 167

def day_off?(date)
  @days_off.each_value do |day_off|
    return true if day_off.call(date)
  end

  false
end

#has_day_off_on(key, &block) ⇒ Object

Provides a function telling that calendar how to evaluate whether a particular day is off. Note that within this block you can use the helper methods week_of, nearest_weekday, next_weekday and previous_weekday:

# Thanksgiving (fourth Thursday of November
MyCalendar.has_day_off_on :thanksgiving do |date|
  date.month == NOVEMBER && date.thursday? && week_of(date) == 4
end

# Christmas (December 25 or nearest weekday)
MyCalendar.has_day_off_on :christmas do |date|
  date.month == DECEMBER && nearest_weekday(date, 25)
end

# New Year's Day (January 1 or next weekday)
MyCalendar.has_day_off_on :new_years do |date|
  date.month == JANUARY && next_weekday(date, 1)
end


147
148
149
# File 'lib/rupee/calendar.rb', line 147

def has_day_off_on(key, &block)
  @days_off[key] = block
end

#has_weekends_offObject

A simple helper method for the commonality among most countries that weekends are not workdays or trading days:

MyCalendar.has_weekends_off


160
161
162
163
164
# File 'lib/rupee/calendar.rb', line 160

def has_weekends_off
  @days_off[:weekends] = Proc.new do |date|
    date.saturday? || date.sunday?
  end
end

#remove_day_off_for(key) ⇒ Object

Removes the day off for the specified key



152
153
154
# File 'lib/rupee/calendar.rb', line 152

def remove_day_off_for(key)
  @days_off.delete key
end