Created
July 5, 2012 13:15
-
-
Save gregory/3053591 to your computer and use it in GitHub Desktop.
Date computation for holidays
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Holidays | |
module DateComputation | |
def holiday?(iso='fr') | |
require_or_load "holidays/#{iso}/computation" | |
holidays = Holidays::const_get(iso.camelize)::Settings.holidays[iso].merge(Holidays::Config::Settings.holidays) | |
holidays.each do |name, settings| | |
holiday_period = Date.from_settings(name, holidays, iso) | |
today_is_holiday = holiday_period.is_a?(Range) ? holiday_period.include?(self) : holiday_period == self | |
return true if today_is_holiday | |
end | |
false | |
end | |
def in_the_holiday_period?(period) | |
period.cover? self | |
end | |
module ClassMethods | |
# Public: Compute a date through Computation module | |
# | |
# name - the name of the method | |
# iso - the iso namespace | |
# | |
# Examples | |
# | |
# from_compute('easter', 'fr') | |
# # => '2012-04-08' | |
# | |
# Returns a Date. | |
def from_compute(name, iso) | |
require_or_load "holidays/#{iso}/computation" | |
Holidays::const_get(iso.camelize)::Computation.send name | |
end | |
# Public: Compute a date from a hash | |
# | |
# options - Hash: | |
# - 'month': Integer for the month to compute | |
# - 'day': Integer for the day to compute | |
# | |
# Examples | |
# | |
# options = | |
# { | |
# 'month' => 4, | |
# 'day' => 8 | |
# } | |
# from_day(options) | |
# # => '2012-04-08' | |
# | |
# Returns a Date | |
def from_day(options) | |
Date.strptime("#{options['month']}-#{options['day']}", '%m-%d') | |
end | |
# Public: Compute a date from a structured hash | |
# | |
# holiday_name - String of the holiday's name | |
# settings - Hash containing all the holidays | |
# | |
# Examples | |
# | |
# options = | |
# { | |
# 'sunday_of_pentecost' => | |
# { | |
# 'type' => :referred, | |
# 'references' => 'other', | |
# 'delta' => 7.weeks | |
# }, | |
# 'other' => | |
# { | |
# 'type' => :day, | |
# 'month' => 4, | |
# 'day' => 8 | |
# } | |
# } | |
# from_settings('sunday_of_pentecost', options, 'fr') | |
# # => '2012-04-08' | |
# | |
# Returns the duplicated String. | |
def from_settings(holiday_name, settings, iso, stack=[]) | |
options = settings[holiday_name] | |
return case options['type'] | |
when :computed then | |
from_compute(holiday_name, iso) | |
when :day then | |
from_day(options) | |
when :period then | |
date_begin = Date.parse("#{Date.today.year}-#{options['month']}-#{options['day']}") | |
(date_begin..(date_begin + options['delta'])) | |
when :referred then | |
raise Holidays::CircularDependencyException if stack.include? options['references'] | |
stack << options['references'] | |
Date.from_settings(options['references'], settings, iso, stack) + options['delta'] | |
end | |
end | |
end | |
def self.included(klass) | |
klass.extend ClassMethods | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
describe Holidays::DateComputation do | |
let(:iso) { 'fr' } | |
let(:settings) do | |
{ | |
'easter' => | |
{ | |
'type' => :computed | |
}, | |
'sunday_of_pentecost' => | |
{ | |
'type' => :referred, | |
'references' => 'easter', | |
'delta' => 7.weeks | |
}, | |
'other' => | |
{ | |
'type' => :referred, | |
'references' => 'easter', | |
'delta' => - 7.weeks | |
}, | |
'national_day' => | |
{ | |
'type' => :day, | |
'month' => 7, | |
'day' => 14 | |
}, | |
'fukuoka' => | |
{ | |
'type' => :period, | |
'month' => 05, | |
'day' => 03, | |
'delta' => 1.month | |
}, | |
'fukushima' => | |
{ | |
'type' => :reffered, | |
'references' => 'fukuoka', | |
'delta' => 1.week | |
}, | |
'xmass' => | |
{ | |
'type' => :day, | |
'month' => 12, | |
'day' => 25 | |
} | |
} | |
end | |
let(:today) { Date.parse("#{Date.today.year}-01-01") } | |
let(:easter) { Date.parse("#{Date.today.year}-04-08") } | |
describe '#holiday?' do | |
context 'when today is in a holiday period' do | |
let(:today) { Date.parse("#{Date.today.year}-05-6") } | |
it 'return true' do | |
today.holiday?.should == true | |
end | |
end | |
context 'when today is a holiday day' do | |
let(:today) { Date.parse("#{Date.today.year}-12-25") } | |
it 'return true' do | |
today.holiday?.should == true | |
end | |
end | |
context 'when today is a holiday reffered to another' do | |
let(:today) { easter + 7.weeks } | |
it 'return true' do | |
today.holiday?.should == true | |
end | |
end | |
context 'when today is a computed holiday ' do | |
let(:today) { easter } | |
it 'return true' do | |
today.holiday?.should == true | |
end | |
end | |
end | |
describe '#in_the_holiday_period?(period)' do | |
let (:holiday_period) do | |
(easter..(easter + 7.weeks)) | |
end | |
it 'return true if today is in the period' do | |
easter.send(:in_the_holiday_period?, holiday_period).should == true | |
end | |
it 'return true if today the last day of the period' do | |
(easter + 7.weeks).send(:in_the_holiday_period?, holiday_period).should == true | |
end | |
it 'return false if today is not in the period' do | |
today.send(:in_the_holiday_period?, holiday_period).should == false | |
end | |
end | |
describe '.from_compute(name)' do | |
context 'when name is easter' do | |
let (:name) { 'easter' } | |
it 'return the easter holiday date' do | |
Date.from_compute(name, iso).should == easter | |
end | |
end | |
end | |
describe '.from_day(options)' do | |
context 'when today is xmass' do | |
it 'return the date of today' do | |
Date.from_day(settings['xmass']).should == Date.strptime("12-25", '%m-%d') | |
end | |
end | |
end | |
describe '.from_settings(name, settings)' do | |
context 'when setting type is period' do | |
it 'return a period' do | |
date_begin = Date.from_day(settings['fukuoka']) | |
Date.from_settings('fukuoka', settings, iso).should == (date_begin..(date_begin + settings['fukuoka']['delta'])) | |
end | |
end | |
context 'when setting type is computed' do | |
it 'return date from compute' do | |
Date.from_settings('easter', settings, iso).should == Date.from_compute('easter', 'fr') | |
end | |
end | |
context 'when setting type is day' do | |
it 'return date from day' do | |
Date.from_settings('national_day', settings, iso).should == Date.from_day(settings['national_day']) | |
end | |
end | |
context 'when setting type is referred' do | |
it 'return date with a delta from refered date' do | |
options = settings['sunday_of_pentecost'] | |
Date.from_settings('sunday_of_pentecost', settings, iso).should == | |
Date.from_settings(options['references'], settings, iso) + options['delta'] | |
end | |
context 'when days_before is an option set to 7' do | |
it 'returns 7 weeks before easter' do | |
options = settings['other'] | |
Date.stub(:from_settings, settings).and_return(Date.from_compute(options['references'], iso)) | |
(Date.from_settings(options['references'], settings, iso) + options['delta']).should == easter - 7.weeks | |
end | |
end | |
context 'when days_after is an options set to 7' do | |
it 'returns 7 weeks after easter' do | |
options = settings['sunday_of_pentecost'] | |
Date.stub(:from_settings, settings).and_return(Date.from_compute(options['references'], iso)) | |
(Date.from_settings(options['references'], settings, iso) + options['delta']).should == easter + 7.weeks | |
end | |
end | |
context 'when reference is a period' do | |
it 'return the the range shifted from delta?' | |
end | |
context 'when reference is included more than once' do | |
let(:options) do | |
{ | |
'sunday_of_pentecost' => | |
{ | |
'type' => :referred, | |
'references' => 'other', | |
'delta' => 7.weeks | |
}, | |
'other' => | |
{ | |
'type' => :referred, | |
'references' => 'sunday_of_pentecost', | |
'delta' => - 7.weeks | |
} | |
} | |
end | |
it 'raise Holidays::CircularDependencyException' do | |
lambda { Date.from_settings('sunday_of_pentecost', options, iso) }.should raise_exception(Holidays::CircularDependencyException) | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
holidays: | |
fr: | |
easter: | |
type: :computed | |
sunday_of_pentecost: | |
type: :referred | |
references: 'easter' | |
delta: <%= 7.weeks %> | |
other: | |
type: :referred | |
references: 'easter' | |
delta: <%= - 1.weeks %> | |
national_day: | |
type: :day | |
month: 7 | |
day: 14 | |
fukuoka: | |
type: :period | |
month: 5 | |
day: 3 | |
delta: <%= 1.month %> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment