Initial import
This commit is contained in:
commit
7268ece923
6 changed files with 308 additions and 0 deletions
48
README
Normal file
48
README
Normal file
|
@ -0,0 +1,48 @@
|
|||
holidays
|
||||
by FIX (your name)
|
||||
FIX (url)
|
||||
|
||||
== DESCRIPTION:
|
||||
|
||||
FIX (describe your package)
|
||||
|
||||
== FEATURES/PROBLEMS:
|
||||
|
||||
* FIX (list of features or problems)
|
||||
|
||||
== SYNOPSIS:
|
||||
|
||||
FIX (code sample of usage)
|
||||
|
||||
== REQUIREMENTS:
|
||||
|
||||
* FIX (list of requirements)
|
||||
|
||||
== INSTALL:
|
||||
|
||||
* FIX (sudo gem install, anything else)
|
||||
|
||||
== LICENSE:
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2007 FIX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
149
lib/holidays.rb
Normal file
149
lib/holidays.rb
Normal file
|
@ -0,0 +1,149 @@
|
|||
|
||||
# === References
|
||||
# ==== Calculations
|
||||
# * http://michaelthompson.org/technikos/holidays.php
|
||||
# ==== World
|
||||
# * http://en.wikipedia.org/wiki/List_of_holidays_by_country
|
||||
# ==== US
|
||||
# * http://www.opm.gov/Operating_Status_Schedules/fedhol/index.asp
|
||||
# * http://www.smart.net/~mmontes/ushols.html
|
||||
module Holidays
|
||||
# Exception class for dealing with unknown regions.
|
||||
class UnkownRegionError < StandardError; end
|
||||
|
||||
VERSION = '1.0.0'
|
||||
|
||||
HOLIDAY_REGIONS = {:ca => 'Canada', :us => 'United States'}
|
||||
WEEKS = {:first => 1, :second => 2, :third => 3, :fourth => 4, :fifth => 5, :last => -1}
|
||||
MONTH_LENGTHS = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
|
||||
|
||||
# :wday: Day of the week (0 is Sunday, 6 is Saturday)
|
||||
HOLIDAYS_BY_MONTH = {
|
||||
1 => [{:mday => 1, :name => 'New Year\'s Day', :regions => [:us, :ca]},
|
||||
{:mday => 6, :name => 'Epiphany Day', :regions => [:gr]},
|
||||
{:wday => 1, :week => :third, :name => 'Martin Luther King, Jr. Day', :regions => [:us]}],
|
||||
3 => [{:wday => 1, :week => :third, :name => 'George Washington\'s Birthday', :regions => [:us]},
|
||||
{:mday => 25, :name => 'Independence Day', :regions => [:gr]}],
|
||||
5 => [{:mday => 1, :name => 'Labour Day', :regions => [:fr,:gr]},
|
||||
{:mday => 8, :name => 'Victoria 1945', :regions => [:fr]},
|
||||
{:wday => 6, :week => :third, :name => 'Armed Forces Day', :regions => [:us]},
|
||||
{:wday => 1, :week => :last, :name => 'Memorial Day', :regions => [:us]}],
|
||||
6 => [{:mday => 14, :name => 'Flag Day', :regions => [:us]}],
|
||||
7 => [{:mday => 4, :name => 'Independence Day', :regions => [:us]},
|
||||
{:mday => 14, :name => 'Ascension Day', :regions => [:fr]}],
|
||||
8 => [{:mday => 15, :name => 'Assumption of Mary', :regions => [:fr, :gr, :christ]}],
|
||||
9 => [{:wday => 1, :week => :first,:name => 'Labor Day', :regions => [:us]},
|
||||
{:wday => 1, :week => :first,:name => 'Labour Day', :regions => [:ca]}],
|
||||
10 => [{:wday => 1, :week => :second, :name => 'Columbus Day', :regions => [:us]},
|
||||
{:mday => 28, :name => 'National Day', :regions => [:gr]}],
|
||||
11 => [{:wday => 4, :week => :fourth, :name => 'Thanksgiving Day', :regions => [:us]},
|
||||
{:mday => 11, :name => 'Rememberance Day', :regions => [:ca]},
|
||||
{:mday => 11, :name => 'Armistice 1918', :regions => [:fr]},
|
||||
{:mday => 1, :name => 'Touissant', :regions => [:fr]}],
|
||||
12 => [{:mday => 25, :name => 'Christmas Day', :regions => [:us,:ca,:christ]},
|
||||
{:mday => 26, :name => 'Boxing Day', :regions => [:ca,:gr]}]
|
||||
}
|
||||
|
||||
# Get all holidays on a certain date
|
||||
def self.lookup_holidays(date, regions = [:ca, :us])
|
||||
#raise(UnkownRegionError, "No holiday information is available for region '#{region}'") unless known_region?(region)
|
||||
|
||||
regions = [regions] unless regions.kind_of?(Array)
|
||||
hbm = HOLIDAYS_BY_MONTH[date.mon]
|
||||
|
||||
holidays = []
|
||||
|
||||
year = date.year
|
||||
month = date.month
|
||||
mday = date.mday
|
||||
wday = date.wday
|
||||
|
||||
hbm.each do |h|
|
||||
# start with the region check
|
||||
next unless h[:regions].any?{ |reg| regions.include?(reg) }
|
||||
|
||||
if h[:mday] and h[:mday] == mday
|
||||
# fixed day of the month
|
||||
holidays << h
|
||||
elsif h[:wday] == wday
|
||||
# by week calculation
|
||||
if calculate_mday(year, month, h[:week], h[:wday]) == mday
|
||||
holidays << h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
holidays
|
||||
end
|
||||
|
||||
#def self.calculate_mday(yr, mo, wday, int)
|
||||
# earliest = 1 + 7 * (int - 1)
|
||||
|
||||
# wd = Date.civil(yr, mo, earliest).wday
|
||||
# if wday == earliest
|
||||
# off = 0
|
||||
# else
|
||||
# if wday < wd
|
||||
# off = wday + (7 - wd)
|
||||
# else
|
||||
# off = (wday + (7 - wd)) - 7
|
||||
# end
|
||||
# end
|
||||
|
||||
# earliest + off
|
||||
# end
|
||||
|
||||
# Calculate the day of the month based on week and day of the week.
|
||||
#
|
||||
# First Monday of Jan, 2008
|
||||
# calculate_mday(2008, 1, :first, :monday)
|
||||
#
|
||||
# Third Thursday of Dec, 2008
|
||||
# calculate_mday(2008, 12, :third, 4)
|
||||
#
|
||||
# Last Monday of Jan, 2008
|
||||
# calculate_mday(2008, 1, :last, 1)
|
||||
#--
|
||||
# see http://www.irt.org/articles/js050/index.htm
|
||||
def self.calculate_mday(year, month, week, wday)
|
||||
raise ArgumentError, "Week paramater must be one of Holidays::WEEKS" unless WEEKS.include?(week)
|
||||
|
||||
nth = WEEKS[week]
|
||||
|
||||
if nth > 0
|
||||
return (nth-1)*7 + 1 + (7 + wday - Date.civil(year, month,(nth-1)*7 + 1).wday)%7
|
||||
end
|
||||
|
||||
days = MONTH_LENGTHS[month]
|
||||
if month == 2 and Date.civil(year,1,1).leap?
|
||||
days = 29
|
||||
end
|
||||
|
||||
return days - (Date.civil(year, month, days).wday - wday + 8)%7;
|
||||
end
|
||||
|
||||
def self.holidays_in_range(from, to, regions = [:ca,:us])
|
||||
regions = [regions] unless regions.kind_of?(Array)
|
||||
holidays = []
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class Date
|
||||
include Holidays
|
||||
|
||||
# Date.civil('2008-01-01').is_holiday?(:us)
|
||||
def is_holiday?(region = 'us')
|
||||
region = region.to_sym
|
||||
|
||||
holidays = Holidays.lookup_holidays(self, region)
|
||||
if holidays
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
15
rakefile.rb
Normal file
15
rakefile.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'fileutils'
|
||||
require 'lib/holidays'
|
||||
|
||||
desc 'Run the unit tests.'
|
||||
Rake::TestTask.new do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'lib/test'
|
||||
t.test_files = FileList['test/test*.rb'].exclude('test_helper.rb')
|
||||
t.verbose = false
|
||||
end
|
||||
|
19
test/benchmark.rb
Normal file
19
test/benchmark.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
require 'date'
|
||||
require 'benchmark'
|
||||
|
||||
|
||||
n = 10000
|
||||
Benchmark.bm do |x|
|
||||
x.report('calculate_mday') do
|
||||
n.times do
|
||||
|
||||
Holidays.calculate_mday(2008, 1, 1, 3)
|
||||
end
|
||||
end
|
||||
x.report('calculate_mdaya') do
|
||||
n.times do
|
||||
Holidays.calculate_mdaya(:third, 1, 1, 2008)
|
||||
end
|
||||
end
|
||||
end
|
5
test/test_helper.rb
Normal file
5
test/test_helper.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__), '../'))
|
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__), '../lib/'))
|
||||
require 'rubygems'
|
||||
require 'test/unit'
|
||||
require 'holidays'
|
72
test/test_holidays.rb
Normal file
72
test/test_holidays.rb
Normal file
|
@ -0,0 +1,72 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
require 'date'
|
||||
# Test cases for reading and generating CSS shorthand properties
|
||||
class HolidayTests < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
@date = Date.civil(2008,1,1)
|
||||
end
|
||||
|
||||
def test_extending_date_class
|
||||
assert @date.respond_to?('is_holiday?')
|
||||
end
|
||||
|
||||
def test_calculating_mdays
|
||||
assert_equal 21, Holidays.calculate_mday(2008, 1, :third, 1)
|
||||
assert_equal 1, Holidays.calculate_mday(2007, 1, :first, 1)
|
||||
assert_equal 2, Holidays.calculate_mday(2007, 3, :first, 5)
|
||||
assert_equal 25, Holidays.calculate_mday(2008, 5, :last, 1)
|
||||
|
||||
|
||||
# Labour day
|
||||
assert_equal 3, Holidays.calculate_mday(2007, 9, :first, 1)
|
||||
assert_equal 1, Holidays.calculate_mday(2008, 9, :first, 1)
|
||||
assert_equal 7, Holidays.calculate_mday(2009, 9, :first, 1)
|
||||
assert_equal 5, Holidays.calculate_mday(2011, 9, :first, 1)
|
||||
assert_equal 5, Holidays.calculate_mday(2050, 9, :first, 1)
|
||||
assert_equal 4, Holidays.calculate_mday(2051, 9, :first, 1)
|
||||
|
||||
# Canadian thanksgiving
|
||||
assert_equal 8, Holidays.calculate_mday(2007, 10, :second, 1)
|
||||
assert_equal 13, Holidays.calculate_mday(2008, 10, :second, 1)
|
||||
assert_equal 12, Holidays.calculate_mday(2009, 10, :second, 1)
|
||||
assert_equal 11, Holidays.calculate_mday(2010, 10, :second, 1)
|
||||
|
||||
end
|
||||
|
||||
def test_region_params
|
||||
holidays = Holidays.lookup_holidays(@date, :us)
|
||||
assert_equal 1, holidays.length
|
||||
|
||||
holidays = Holidays.lookup_holidays(@date, [:us,:ca])
|
||||
assert_equal 1, holidays.length
|
||||
end
|
||||
|
||||
def test_lookup_holidays_spot_checks
|
||||
h = Holidays.lookup_holidays(Date.civil(2008,5,1), :gr)
|
||||
assert_equal 'Labour Day', h[0][:name]
|
||||
|
||||
h = Holidays.lookup_holidays(Date.civil(2045,11,1), :fr)
|
||||
assert_equal 'Touissant', h[0][:name]
|
||||
end
|
||||
|
||||
def test_lookup_holidays_and_iterate
|
||||
holidays = Holidays.lookup_holidays(@date, :ca)
|
||||
holidays.each do |h|
|
||||
puts h[:name]
|
||||
end
|
||||
end
|
||||
|
||||
def test_lookup_holiday
|
||||
holidays = Holidays.lookup_holidays(Date.civil(2008,1,21), :ca)
|
||||
assert_equal 0, holidays.length
|
||||
|
||||
holidays = Holidays.lookup_holidays(Date.civil(2008,1,21), :us)
|
||||
assert_equal 1, holidays.length
|
||||
end
|
||||
|
||||
def test_basic
|
||||
assert Date.civil(2008,1,1).is_holiday?('ca')
|
||||
end
|
||||
|
||||
end
|
Loading…
Add table
Reference in a new issue