bjeanes-holidays 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +15 -0
- data/LICENSE +21 -0
- data/README.rdoc +77 -0
- data/REFERENCES +16 -0
- data/data/SYNTAX +111 -0
- data/data/au.yaml +111 -0
- data/data/build_defs.rb +152 -0
- data/data/ca.yaml +141 -0
- data/data/de.yaml +111 -0
- data/data/dk.yaml +117 -0
- data/data/es.yaml +161 -0
- data/data/fr.yaml +70 -0
- data/data/gb.yaml +106 -0
- data/data/ie.yaml +58 -0
- data/data/index.yaml +23 -0
- data/data/is.yaml +136 -0
- data/data/it.yaml +66 -0
- data/data/mx.yaml +106 -0
- data/data/nl.yaml +67 -0
- data/data/north_america_informal.yaml +49 -0
- data/data/nyse.yaml +63 -0
- data/data/pt.yaml +85 -0
- data/data/se.yaml +91 -0
- data/data/united_nations.yaml +188 -0
- data/data/ups.yaml +56 -0
- data/data/us.yaml +81 -0
- data/data/za.yaml +78 -0
- data/lib/holidays.rb +404 -0
- data/lib/holidays/MANIFEST +25 -0
- data/lib/holidays/au.rb +42 -0
- data/lib/holidays/ca.rb +68 -0
- data/lib/holidays/de.rb +50 -0
- data/lib/holidays/dk.rb +47 -0
- data/lib/holidays/es.rb +52 -0
- data/lib/holidays/europe.rb +214 -0
- data/lib/holidays/fr.rb +36 -0
- data/lib/holidays/gb.rb +40 -0
- data/lib/holidays/ie.rb +32 -0
- data/lib/holidays/is.rb +61 -0
- data/lib/holidays/it.rb +35 -0
- data/lib/holidays/mx.rb +51 -0
- data/lib/holidays/nl.rb +36 -0
- data/lib/holidays/north_america.rb +107 -0
- data/lib/holidays/nyse.rb +32 -0
- data/lib/holidays/pt.rb +43 -0
- data/lib/holidays/scandinavia.rb +114 -0
- data/lib/holidays/se.rb +52 -0
- data/lib/holidays/united_nations.rb +24 -0
- data/lib/holidays/ups.rb +31 -0
- data/lib/holidays/us.rb +48 -0
- data/lib/holidays/za.rb +35 -0
- data/rakefile.rb +150 -0
- data/test/defs/test_defs_au.rb +36 -0
- data/test/defs/test_defs_ca.rb +29 -0
- data/test/defs/test_defs_de.rb +49 -0
- data/test/defs/test_defs_dk.rb +30 -0
- data/test/defs/test_defs_es.rb +57 -0
- data/test/defs/test_defs_europe.rb +243 -0
- data/test/defs/test_defs_fr.rb +26 -0
- data/test/defs/test_defs_gb.rb +36 -0
- data/test/defs/test_defs_ie.rb +21 -0
- data/test/defs/test_defs_is.rb +33 -0
- data/test/defs/test_defs_it.rb +25 -0
- data/test/defs/test_defs_mx.rb +22 -0
- data/test/defs/test_defs_nl.rb +24 -0
- data/test/defs/test_defs_north_america.rb +54 -0
- data/test/defs/test_defs_nyse.rb +22 -0
- data/test/defs/test_defs_pt.rb +56 -0
- data/test/defs/test_defs_scandinavia.rb +75 -0
- data/test/defs/test_defs_se.rb +32 -0
- data/test/defs/test_defs_ups.rb +21 -0
- data/test/defs/test_defs_us.rb +23 -0
- data/test/defs/test_defs_za.rb +25 -0
- metadata +132 -0
@@ -0,0 +1,188 @@
|
|
1
|
+
# United Nationas holiday definitions for the Ruby Holiday gem.
|
2
|
+
# Updated 2008-11-21.
|
3
|
+
---
|
4
|
+
2:
|
5
|
+
- name: International Mother Language Day
|
6
|
+
regions: [un]
|
7
|
+
mday: 2
|
8
|
+
3:
|
9
|
+
- name: United Nations Day for Women's Rights and International Peace
|
10
|
+
regions: [un]
|
11
|
+
mday: 8
|
12
|
+
- name: International Day for the Elimination of Racial Discrimination
|
13
|
+
regions: [un]
|
14
|
+
mday: 21
|
15
|
+
- name: Beginning of the Week of Solidarity with the Peoples Struggling against Racism and Racial Discrimination
|
16
|
+
regions: [un]
|
17
|
+
mday: 21
|
18
|
+
- name: World Day for Water
|
19
|
+
regions: [un]
|
20
|
+
mday: 22
|
21
|
+
- name: World Meteorological Day
|
22
|
+
regions: [un]
|
23
|
+
mday: 23
|
24
|
+
4:
|
25
|
+
- name: World Health Day
|
26
|
+
regions: [un]
|
27
|
+
mday: 7
|
28
|
+
- name: World Book and Copyright Day
|
29
|
+
regions: [un]
|
30
|
+
mday: 23
|
31
|
+
5:
|
32
|
+
- name: World Press Freedom Day
|
33
|
+
regions: [un]
|
34
|
+
mday: 3
|
35
|
+
- name: International Day of Families
|
36
|
+
regions: [un]
|
37
|
+
mday: 15
|
38
|
+
- name: World Telecommunication Day
|
39
|
+
regions: [un]
|
40
|
+
mday: 17
|
41
|
+
- name: World Day for Cultural Diversity for Dialogue and Development
|
42
|
+
regions: [un]
|
43
|
+
mday: 21
|
44
|
+
- name: International Day for Biological Diversity
|
45
|
+
regions: [un]
|
46
|
+
mday: 22
|
47
|
+
- name: Beginning of the Week of Solidarity with the Peoples of Non-Self-Governing Territories
|
48
|
+
regions: [un]
|
49
|
+
mday: 25
|
50
|
+
- name: International Day of United Nations Peacekeepers
|
51
|
+
regions: [un]
|
52
|
+
mday: 29
|
53
|
+
- name: World No-Tobacco Day
|
54
|
+
regions: [un]
|
55
|
+
mday: 31
|
56
|
+
6:
|
57
|
+
- name: International Day of Innocent Children Victims of Aggression
|
58
|
+
regions: [un]
|
59
|
+
mday: 4
|
60
|
+
- name: World Environment Day
|
61
|
+
regions: [un]
|
62
|
+
mday: 5
|
63
|
+
- name: World Day to Combat Desertification and Drought
|
64
|
+
regions: [un]
|
65
|
+
mday: 17
|
66
|
+
- name: World Refugee Day
|
67
|
+
regions: [un]
|
68
|
+
mday: 20
|
69
|
+
- name: United Nations Public Service Day
|
70
|
+
regions: [un]
|
71
|
+
mday: 23
|
72
|
+
- name: International Day against Drug Abuse and Illicit Trafficking
|
73
|
+
regions: [un]
|
74
|
+
mday: 26
|
75
|
+
- name: International Day in Support of Victims of Torture
|
76
|
+
regions: [un]
|
77
|
+
mday: 26
|
78
|
+
7:
|
79
|
+
- name: International Day of Cooperatives
|
80
|
+
week: 1
|
81
|
+
regions: [un]
|
82
|
+
wday: 6
|
83
|
+
- name: World Population Day
|
84
|
+
regions: [un]
|
85
|
+
mday: 11
|
86
|
+
8:
|
87
|
+
- name: International Day of the World's Indigenous People
|
88
|
+
regions: [un]
|
89
|
+
mday: 9
|
90
|
+
- name: International Youth Day
|
91
|
+
regions: [un]
|
92
|
+
mday: 12
|
93
|
+
- name: International Day for the Remembrance of the Slave Trade and Its Abolition
|
94
|
+
regions: [un]
|
95
|
+
mday: 23
|
96
|
+
9:
|
97
|
+
- name: International Literacy Day
|
98
|
+
regions: [un]
|
99
|
+
mday: 8
|
100
|
+
- name: International Day for the Preservation of the Ozone Layer
|
101
|
+
regions: [un]
|
102
|
+
mday: 16
|
103
|
+
- name: International Day of Peace
|
104
|
+
regions: [un]
|
105
|
+
mday: 21
|
106
|
+
- name: International Day of Older Persons
|
107
|
+
regions: [un]
|
108
|
+
mday: 1
|
109
|
+
10:
|
110
|
+
- name: World Space Week
|
111
|
+
regions: [un]
|
112
|
+
mday: 4
|
113
|
+
- name: World Teachers' Day
|
114
|
+
regions: [un]
|
115
|
+
mday: 5
|
116
|
+
- name: World Habitat Day
|
117
|
+
week: 1
|
118
|
+
regions: [un]
|
119
|
+
wday: 1
|
120
|
+
- name: International Day for Natural Disaster Reduction
|
121
|
+
week: 2
|
122
|
+
regions: [un]
|
123
|
+
wday: 3
|
124
|
+
- name: World Post Day
|
125
|
+
regions: [un]
|
126
|
+
mday: 9
|
127
|
+
- name: World Mental Health Day
|
128
|
+
regions: [un]
|
129
|
+
mday: 10
|
130
|
+
- name: World Food Day
|
131
|
+
regions: [un]
|
132
|
+
mday: 16
|
133
|
+
- name: International Day for the Eradication of Poverty
|
134
|
+
regions: [un]
|
135
|
+
mday: 17
|
136
|
+
- name: United Nations Day
|
137
|
+
regions: [un]
|
138
|
+
mday: 24
|
139
|
+
- name: World Development Information Day
|
140
|
+
regions: [un]
|
141
|
+
mday: 24
|
142
|
+
- name: Disarmament Week
|
143
|
+
regions: [un]
|
144
|
+
mday: 24
|
145
|
+
11:
|
146
|
+
- name: International Day for Preventing the Exploitation of the Environment in War and Armed Conflict
|
147
|
+
regions: [un]
|
148
|
+
mday: 6
|
149
|
+
- name: International Day for Tolerance
|
150
|
+
regions: [un]
|
151
|
+
mday: 16
|
152
|
+
- name: Africa Industrialization Day
|
153
|
+
regions: [un]
|
154
|
+
mday: 20
|
155
|
+
- name: Universal Children's Day
|
156
|
+
regions: [un]
|
157
|
+
mday: 20
|
158
|
+
- name: World Television Day
|
159
|
+
regions: [un]
|
160
|
+
mday: 21
|
161
|
+
- name: International Day for the Elimination of Violence against Women
|
162
|
+
regions: [un]
|
163
|
+
mday: 25
|
164
|
+
- name: International Day of Solidarity with the Palestinian People
|
165
|
+
regions: [un]
|
166
|
+
mday: 29
|
167
|
+
12:
|
168
|
+
- name: World AIDS Day
|
169
|
+
regions: [un]
|
170
|
+
mday: 1
|
171
|
+
- name: International Day for the Abolition of Slavery
|
172
|
+
regions: [un]
|
173
|
+
mday: 2
|
174
|
+
- name: International Day of Disabled Persons
|
175
|
+
regions: [un]
|
176
|
+
mday: 3
|
177
|
+
- name: International Volunteer Day for Economic and Social Development
|
178
|
+
regions: [un]
|
179
|
+
mday: 5
|
180
|
+
- name: International Civil Aviation Day
|
181
|
+
regions: [un]
|
182
|
+
mday: 7
|
183
|
+
- name: Human Rights Day
|
184
|
+
regions: [un]
|
185
|
+
mday: 10
|
186
|
+
- name: International Migrants Day
|
187
|
+
regions: [un]
|
188
|
+
mday: 18
|
data/data/ups.yaml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# UPS holiday definitions for the Ruby Holiday gem.
|
2
|
+
#
|
3
|
+
# By Tim Anglade
|
4
|
+
#
|
5
|
+
# Updated: 2008-09-23.
|
6
|
+
# Source: http://www.ups.com/content/us/en/resources/ship/imp_exp/operation.html
|
7
|
+
---
|
8
|
+
months:
|
9
|
+
1:
|
10
|
+
- name: New Year's Day
|
11
|
+
regions: [ups]
|
12
|
+
mday: 1
|
13
|
+
observed: to_weekday_if_weekend
|
14
|
+
5:
|
15
|
+
- name: Memorial Day
|
16
|
+
week: -1
|
17
|
+
regions: [ups]
|
18
|
+
wday: 1
|
19
|
+
7:
|
20
|
+
- name: Independence Day
|
21
|
+
regions: [ups]
|
22
|
+
mday: 4
|
23
|
+
observed: to_weekday_if_weekend
|
24
|
+
9:
|
25
|
+
- name: Labor Day
|
26
|
+
week: 1
|
27
|
+
regions: [ups]
|
28
|
+
wday: 1
|
29
|
+
11:
|
30
|
+
- name: Thanksgiving
|
31
|
+
week: 4
|
32
|
+
regions: [ups]
|
33
|
+
wday: 4
|
34
|
+
- name: Day After Thanksgiving
|
35
|
+
week: 4
|
36
|
+
regions: [ups]
|
37
|
+
wday: 5
|
38
|
+
12:
|
39
|
+
- name: Christmas Day
|
40
|
+
regions: [ups]
|
41
|
+
mday: 25
|
42
|
+
observed: to_weekday_if_weekend
|
43
|
+
- name: New Year's Eve
|
44
|
+
regions: [ups]
|
45
|
+
mday: 31
|
46
|
+
tests: |
|
47
|
+
{Date.civil(2008,1,1) => 'New Year\'s Day',
|
48
|
+
Date.civil(2008,5,26) => 'Memorial Day',
|
49
|
+
Date.civil(2008,7,4) => 'Independence Day',
|
50
|
+
Date.civil(2008,9,1) => 'Labor Day',
|
51
|
+
Date.civil(2008,11,27) => 'Thanksgiving',
|
52
|
+
Date.civil(2008,11,28) => 'Day After Thanksgiving',
|
53
|
+
Date.civil(2008,12,25) => 'Christmas Day',
|
54
|
+
Date.civil(2008,12,31) => 'New Year\'s Eve',}.each do |date, name|
|
55
|
+
assert_equal name, Holidays.on(date, :ups)[0][:name]
|
56
|
+
end
|
data/data/us.yaml
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# United States holiday definitions for the Ruby Holiday gem.
|
2
|
+
#
|
3
|
+
# Updated: 2008-11-24.
|
4
|
+
# Source: http://en.wikipedia.org/wiki/Public_holidays_of_the_United_States
|
5
|
+
---
|
6
|
+
months:
|
7
|
+
0:
|
8
|
+
- name: Good Friday
|
9
|
+
regions: [us]
|
10
|
+
function: easter(year)-2
|
11
|
+
type: informal
|
12
|
+
1:
|
13
|
+
- name: New Year's Day
|
14
|
+
regions: [us]
|
15
|
+
mday: 1
|
16
|
+
observed: to_weekday_if_weekend
|
17
|
+
- name: Martin Luther King, Jr. Day
|
18
|
+
week: 3
|
19
|
+
regions: [us]
|
20
|
+
wday: 1
|
21
|
+
- name: Inauguration Day
|
22
|
+
function: us_inauguration_day(year)
|
23
|
+
regions: [us_dc]
|
24
|
+
2:
|
25
|
+
- name: Presidents' Day
|
26
|
+
week: 3
|
27
|
+
regions: [us]
|
28
|
+
wday: 1
|
29
|
+
5:
|
30
|
+
- name: Memorial Day
|
31
|
+
week: -1
|
32
|
+
regions: [us]
|
33
|
+
wday: 1
|
34
|
+
7:
|
35
|
+
- name: Independence Day
|
36
|
+
regions: [us]
|
37
|
+
mday: 4
|
38
|
+
observed: to_weekday_if_weekend
|
39
|
+
9:
|
40
|
+
- name: Labor Day
|
41
|
+
week: 1
|
42
|
+
regions: [us]
|
43
|
+
wday: 1
|
44
|
+
10:
|
45
|
+
- name: Columbus Day
|
46
|
+
week: 2
|
47
|
+
regions: [us]
|
48
|
+
wday: 1
|
49
|
+
11:
|
50
|
+
- name: Veterans Day
|
51
|
+
regions: [us]
|
52
|
+
mday: 11
|
53
|
+
observed: to_weekday_if_weekend
|
54
|
+
- name: Thanksgiving
|
55
|
+
week: 4
|
56
|
+
regions: [us]
|
57
|
+
wday: 4
|
58
|
+
12:
|
59
|
+
- name: Christmas Day
|
60
|
+
regions: [us]
|
61
|
+
mday: 25
|
62
|
+
observed: to_weekday_if_weekend
|
63
|
+
methods:
|
64
|
+
us_inauguration_day: |
|
65
|
+
# January 20, every fourth year, following Presidential election
|
66
|
+
def self.us_inauguration_day(year)
|
67
|
+
year % 4 == 1 ? 20 : nil
|
68
|
+
end
|
69
|
+
tests: |
|
70
|
+
{Date.civil(2008,1,1) => 'New Year\'s Day',
|
71
|
+
Date.civil(2008,1,21) => 'Martin Luther King, Jr. Day',
|
72
|
+
Date.civil(2008,2,18) => 'Presidents\' Day',
|
73
|
+
Date.civil(2008,5,26) => 'Memorial Day',
|
74
|
+
Date.civil(2008,7,4) => 'Independence Day',
|
75
|
+
Date.civil(2008,9,1) => 'Labor Day',
|
76
|
+
Date.civil(2008,10,13) => 'Columbus Day',
|
77
|
+
Date.civil(2008,11,11) => 'Veterans Day',
|
78
|
+
Date.civil(2008,11,27) => 'Thanksgiving',
|
79
|
+
Date.civil(2008,12,25) => 'Christmas Day'}.each do |date, name|
|
80
|
+
assert_equal name, Holidays.on(date, :us)[0][:name]
|
81
|
+
end
|
data/data/za.yaml
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# South African holiday definitions for the Ruby Holiday gem.
|
2
|
+
#
|
3
|
+
# Updated: 2008-11-29.
|
4
|
+
# Sources:
|
5
|
+
# - http://en.wikipedia.org/wiki/Public_holidays_in_South_Africa
|
6
|
+
# - http://www.info.gov.za/aboutsa/holidays.htm
|
7
|
+
---
|
8
|
+
months:
|
9
|
+
0:
|
10
|
+
- name: Good Friday
|
11
|
+
regions: [za]
|
12
|
+
function: easter(year)-2
|
13
|
+
- name: Family Day
|
14
|
+
regions: [za]
|
15
|
+
function: easter(year)+1
|
16
|
+
1:
|
17
|
+
- name: New Year's Day
|
18
|
+
regions: [za]
|
19
|
+
mday: 1
|
20
|
+
observed: to_monday_if_sunday
|
21
|
+
3:
|
22
|
+
- name: Human Rights Day
|
23
|
+
regions: [za]
|
24
|
+
mday: 21
|
25
|
+
observed: to_monday_if_sunday
|
26
|
+
4:
|
27
|
+
- name: Freedom Day
|
28
|
+
regions: [za]
|
29
|
+
mday: 27
|
30
|
+
observed: to_monday_if_sunday
|
31
|
+
5:
|
32
|
+
- name: Workers Day
|
33
|
+
regions: [za]
|
34
|
+
mday: 1
|
35
|
+
observed: to_monday_if_sunday
|
36
|
+
6:
|
37
|
+
- name: Youth Day
|
38
|
+
regions: [za]
|
39
|
+
mday: 16
|
40
|
+
observed: to_monday_if_sunday
|
41
|
+
8:
|
42
|
+
- name: National Women's Day
|
43
|
+
regions: [za]
|
44
|
+
mday: 9
|
45
|
+
observed: to_monday_if_sunday
|
46
|
+
9:
|
47
|
+
- name: Heritage Day
|
48
|
+
regions: [za]
|
49
|
+
mday: 24
|
50
|
+
observed: to_monday_if_sunday
|
51
|
+
12:
|
52
|
+
- name: Day of Reconciliation
|
53
|
+
regions: [za]
|
54
|
+
mday: 16
|
55
|
+
observed: to_monday_if_sunday
|
56
|
+
- name: Christmas Day
|
57
|
+
regions: [za]
|
58
|
+
mday: 25
|
59
|
+
observed: to_monday_if_sunday
|
60
|
+
- name: Day of Goodwill
|
61
|
+
regions: [za]
|
62
|
+
mday: 26
|
63
|
+
observed: to_weekday_if_boxing_weekend
|
64
|
+
tests: |
|
65
|
+
{Date.civil(2007,1,1) => 'New Year\'s Day',
|
66
|
+
Date.civil(2007,3,21) => 'Human Rights Day',
|
67
|
+
Date.civil(2007,4,6) => 'Good Friday',
|
68
|
+
Date.civil(2007,4,9) => 'Family Day',
|
69
|
+
Date.civil(2007,4,27) => 'Freedom Day',
|
70
|
+
Date.civil(2007,5,1) => 'Workers Day',
|
71
|
+
Date.civil(2007,6,16) => 'Youth Day',
|
72
|
+
Date.civil(2007,8,9) => 'National Women\'s Day',
|
73
|
+
Date.civil(2007,9,24) => 'Heritage Day',
|
74
|
+
Date.civil(2007,12,16) => 'Day of Reconciliation',
|
75
|
+
Date.civil(2007,12,25) => 'Christmas Day',
|
76
|
+
Date.civil(2007,12,26) => 'Day of Goodwill'}.each do |date, name|
|
77
|
+
assert_equal name, Holidays.on(date, :za, :informal)[0][:name]
|
78
|
+
end
|
data/lib/holidays.rb
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
# == Region options
|
7
|
+
# Holidays can be defined as belonging to one or more regions and sub regions.
|
8
|
+
# The Holidays#on, Holidays#between, Date#holidays and Date#holiday? methods
|
9
|
+
# each allow you to specify a specific region.
|
10
|
+
#
|
11
|
+
# There are several different ways that you can specify a region:
|
12
|
+
#
|
13
|
+
# [<tt>:region</tt>]
|
14
|
+
# By region. For example, return holidays in the Canada with <tt>:ca</tt>.
|
15
|
+
# [<tt>:region_</tt>]
|
16
|
+
# By region and sub regions. For example, return holidays in Germany
|
17
|
+
# and all its sub regions with <tt>:de_</tt>.
|
18
|
+
# [<tt>:region_sub</tt>]
|
19
|
+
# By sub region. Return national holidays in Spain plus holidays in Spain's
|
20
|
+
# Valencia region with <tt>:es_v</tt>.
|
21
|
+
# [<tt>:any</tt>]
|
22
|
+
# Any region. Return holidays from any loaded region.
|
23
|
+
#
|
24
|
+
# == Other options
|
25
|
+
# [<tt>:observed</tt>] Return holidays on the day they are observed (e.g. on a Monday if they fall on a Sunday).
|
26
|
+
# [<tt>:informal</tt>] Include informal holidays (e.g. Valentine's Day)
|
27
|
+
#
|
28
|
+
# == Examples
|
29
|
+
# Return all holidays in the <tt>:ca</tt> and <tt>:us</tt> regions on the day that they are
|
30
|
+
# observed.
|
31
|
+
#
|
32
|
+
# Holidays.between(from, to, :ca, :us, :observed)
|
33
|
+
#
|
34
|
+
# Return all holidays in <tt>:ca</tt> and any <tt>:ca</tt> sub-region.
|
35
|
+
#
|
36
|
+
# Holidays.between(from, to, :ca_)
|
37
|
+
#
|
38
|
+
# Return all holidays in <tt>:ca_bc</tt> sub-region (which includes the <tt>:ca</tt>), including informal holidays.
|
39
|
+
#
|
40
|
+
# Holidays.between(from, to, :ca_bc, :informal)
|
41
|
+
module Holidays
|
42
|
+
# Exception thrown when an unknown region is requested.
|
43
|
+
class UnkownRegionError < ArgumentError; end
|
44
|
+
|
45
|
+
VERSION = '0.9.2'
|
46
|
+
|
47
|
+
@@regions = []
|
48
|
+
@@holidays_by_month = {}
|
49
|
+
@@proc_cache = {}
|
50
|
+
|
51
|
+
WEEKS = {:first => 1, :second => 2, :third => 3, :fourth => 4, :fifth => 5, :last => -1, :second_last => -2, :third_last => -3}
|
52
|
+
MONTH_LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
53
|
+
DAY_SYMBOLS = Date::DAYNAMES.collect { |n| n.downcase.intern }
|
54
|
+
|
55
|
+
# Get all holidays on a given date.
|
56
|
+
#
|
57
|
+
# [<tt>date</tt>] A Date object.
|
58
|
+
# [<tt>:options</tt>] One or more region symbols, <tt>:informal</tt> and/or <tt>:observed</tt>.
|
59
|
+
#
|
60
|
+
# Returns an array of hashes or nil. See Holidays#between for the output
|
61
|
+
# format.
|
62
|
+
#
|
63
|
+
# Also available via Date#holidays.
|
64
|
+
def self.on(date, *options)
|
65
|
+
self.between(date, date, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get all holidays occuring between two dates, inclusively.
|
69
|
+
#
|
70
|
+
# Returns an array of hashes or nil.
|
71
|
+
#
|
72
|
+
# Each holiday is returned as a hash with the following fields:
|
73
|
+
# [<tt>start_date</tt>] Ruby Date object.
|
74
|
+
# [<tt>end_date</tt>] Ruby Date object.
|
75
|
+
# [<tt>options</tt>] One or more region symbols, <tt>:informal</tt> and/or <tt>:observed</tt>.
|
76
|
+
#
|
77
|
+
# ==== Example
|
78
|
+
# from = Date.civil(2008,7,1)
|
79
|
+
# to = Date.civil(2008,7,31)
|
80
|
+
#
|
81
|
+
# Holidays.between(from, to, :ca, :us)
|
82
|
+
# => [{:name => 'Canada Day', :regions => [:ca]...}
|
83
|
+
# {:name => 'Independence Day'', :regions => [:us], ...}]
|
84
|
+
def self.between(start_date, end_date, *options)
|
85
|
+
regions, observed, informal = parse_options(options)
|
86
|
+
holidays = []
|
87
|
+
|
88
|
+
dates = {}
|
89
|
+
(start_date..end_date).each do |date|
|
90
|
+
# Always include month '0' for variable-month holidays
|
91
|
+
dates[date.year] = [0] unless dates[date.year]
|
92
|
+
# TODO: test this, maybe should push then flatten
|
93
|
+
dates[date.year] << date.month unless dates[date.year].include?(date.month)
|
94
|
+
end
|
95
|
+
|
96
|
+
dates.each do |year, months|
|
97
|
+
months.each do |month|
|
98
|
+
next unless hbm = @@holidays_by_month[month]
|
99
|
+
|
100
|
+
hbm.each do |h|
|
101
|
+
next unless in_region?(regions, h[:regions])
|
102
|
+
|
103
|
+
# Skip informal holidays unless they have been requested
|
104
|
+
next if h[:type] == :informal and not informal
|
105
|
+
|
106
|
+
if h[:function]
|
107
|
+
# Holiday definition requires a calculation
|
108
|
+
result = call_proc(h[:function], year)
|
109
|
+
|
110
|
+
# Procs may return either Date or an integer representing mday
|
111
|
+
if result.kind_of?(Date)
|
112
|
+
month = result.month
|
113
|
+
mday = result.mday
|
114
|
+
else
|
115
|
+
mday = result
|
116
|
+
end
|
117
|
+
else
|
118
|
+
# Calculate the mday
|
119
|
+
mday = h[:mday] || Date.calculate_mday(year, month, h[:week], h[:wday])
|
120
|
+
end
|
121
|
+
|
122
|
+
# Silently skip bad mdays
|
123
|
+
begin
|
124
|
+
date = Date.civil(year, month, mday)
|
125
|
+
rescue; next; end
|
126
|
+
|
127
|
+
# If the :observed option is set, calculate the date when the holiday
|
128
|
+
# is observed.
|
129
|
+
if observed and h[:observed]
|
130
|
+
date = call_proc(h[:observed], date)
|
131
|
+
end
|
132
|
+
|
133
|
+
if date.between?(start_date, end_date)
|
134
|
+
holidays << {:date => date, :name => h[:name], :regions => h[:regions]}
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
holidays
|
142
|
+
end
|
143
|
+
|
144
|
+
# Merge a new set of definitions into the Holidays module.
|
145
|
+
#
|
146
|
+
# This method is automatically called when including holiday definition
|
147
|
+
# files.
|
148
|
+
def self.merge_defs(regions, holidays) # :nodoc:
|
149
|
+
@@regions = @@regions | regions
|
150
|
+
@@regions.uniq!
|
151
|
+
|
152
|
+
holidays.each do |month, holiday_defs|
|
153
|
+
@@holidays_by_month[month] = [] unless @@holidays_by_month[month]
|
154
|
+
holiday_defs.each do |holiday_def|
|
155
|
+
|
156
|
+
exists = false
|
157
|
+
@@holidays_by_month[month].each do |ex|
|
158
|
+
# TODO: gross.
|
159
|
+
if ex[:name] == holiday_def[:name] and ex[:wday] == holiday_def[:wday] and ex[:mday] == holiday_def[:mday] and ex[:week] == holiday_def[:week] and ex[:function_id] == holiday_def[:function_id] and ex[:type] == holiday_def[:type] and ex[:observed_id] == holiday_def[:observed_id]
|
160
|
+
# append regions
|
161
|
+
ex[:regions] << holiday_def[:regions]
|
162
|
+
|
163
|
+
# Should do this once we're done
|
164
|
+
ex[:regions].flatten!
|
165
|
+
ex[:regions].uniq!
|
166
|
+
exists = true
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
@@holidays_by_month[month] << holiday_def unless exists
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Get the date of Easter Sunday in a given year. From Easter Sunday, it is
|
176
|
+
# possible to calculate many traditional holidays in Western countries.
|
177
|
+
# Returns a Date object.
|
178
|
+
def self.easter(year)
|
179
|
+
y = year
|
180
|
+
a = y % 19
|
181
|
+
b = y / 100
|
182
|
+
c = y % 100
|
183
|
+
d = b / 4
|
184
|
+
e = b % 4
|
185
|
+
f = (b + 8) / 25
|
186
|
+
g = (b - f + 1) / 3
|
187
|
+
h = (19 * a + b - d - g + 15) % 30
|
188
|
+
i = c / 4
|
189
|
+
k = c % 4
|
190
|
+
l = (32 + 2 * e + 2 * i - h - k) % 7
|
191
|
+
m = (a + 11 * h + 22 * l) / 451
|
192
|
+
month = (h + l - 7 * m + 114) / 31
|
193
|
+
day = ((h + l - 7 * m + 114) % 31) + 1
|
194
|
+
Date.civil(year, month, day)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Move date to Monday if it occurs on a Sunday.
|
198
|
+
# Used as a callback function.
|
199
|
+
def self.to_monday_if_sunday(date)
|
200
|
+
date += 1 if date.wday == 0
|
201
|
+
date
|
202
|
+
end
|
203
|
+
|
204
|
+
# Move date to Monday if it occurs on a Saturday on Sunday.
|
205
|
+
# Used as a callback function.
|
206
|
+
def self.to_monday_if_weekend(date)
|
207
|
+
date += 1 if date.wday == 0
|
208
|
+
date += 2 if date.wday == 6
|
209
|
+
date
|
210
|
+
end
|
211
|
+
|
212
|
+
# Move Boxing Day if it falls on a weekend, leaving room for Christmas.
|
213
|
+
# Used as a callback function.
|
214
|
+
def self.to_weekday_if_boxing_weekend(date)
|
215
|
+
date += 2 if date.wday == 6 or date.wday == 0
|
216
|
+
date
|
217
|
+
end
|
218
|
+
|
219
|
+
# Move date to Monday if it occurs on a Sunday or to Friday if it occurs on a
|
220
|
+
# Saturday.
|
221
|
+
# Used as a callback function.
|
222
|
+
def self.to_weekday_if_weekend(date)
|
223
|
+
date += 1 if date.wday == 0
|
224
|
+
date -= 1 if date.wday == 6
|
225
|
+
date
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
# Returns [(arr)regions, (bool)observed, (bool)informal]
|
230
|
+
def self.parse_options(*options) # :nodoc:
|
231
|
+
options.flatten!
|
232
|
+
observed = options.delete(:observed) ? true : false
|
233
|
+
informal = options.delete(:informal) ? true : false
|
234
|
+
regions = parse_regions(options)
|
235
|
+
return regions, observed, informal
|
236
|
+
end
|
237
|
+
|
238
|
+
# Check regions against list of supported regions and return an array of
|
239
|
+
# symbols.
|
240
|
+
#
|
241
|
+
# If a wildcard region is found (e.g. <tt>:ca_</tt>) it is expanded into all
|
242
|
+
# of its available sub regions.
|
243
|
+
def self.parse_regions(regions) # :nodoc:
|
244
|
+
regions = [regions] unless regions.kind_of?(Array)
|
245
|
+
return [:any] if regions.empty?
|
246
|
+
|
247
|
+
regions = regions.collect { |r| r.to_sym }
|
248
|
+
|
249
|
+
# Found sub region wild-card
|
250
|
+
regions.delete_if do |reg|
|
251
|
+
if reg.to_s =~ /_$/
|
252
|
+
regions << @@regions.select { |dr| dr.to_s =~ Regexp.new("^#{reg}") }
|
253
|
+
true
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
regions.flatten!
|
258
|
+
|
259
|
+
raise UnkownRegionError unless regions.all? { |r| r == :any or @@regions.include?(r) }
|
260
|
+
|
261
|
+
regions
|
262
|
+
end
|
263
|
+
|
264
|
+
# Check sub regions.
|
265
|
+
#
|
266
|
+
# When request :any, all holidays should be returned.
|
267
|
+
# When requesting :ca_bc, holidays in :ca or :ca_bc should be returned.
|
268
|
+
# When requesting :ca, holidays in :ca but not its subregions should be returned.
|
269
|
+
def self.in_region?(requested, available) # :nodoc:
|
270
|
+
return true if requested.include?(:any)
|
271
|
+
|
272
|
+
# When an underscore is encountered, derive the parent regions
|
273
|
+
# symbol and include both in the requested array.
|
274
|
+
requested = requested.collect do |r|
|
275
|
+
r.to_s =~ /_/ ? [r, r.to_s.gsub(/_[\w]*$/, '').to_sym] : r
|
276
|
+
end
|
277
|
+
|
278
|
+
requested = requested.flatten.uniq
|
279
|
+
|
280
|
+
available.any? { |avail| requested.include?(avail) }
|
281
|
+
end
|
282
|
+
|
283
|
+
# Call a proc function defined in a holiday definition file.
|
284
|
+
#
|
285
|
+
# Procs are cached.
|
286
|
+
#
|
287
|
+
# ==== Benchmarks
|
288
|
+
#
|
289
|
+
# Lookup Easter Sunday, with caching, by number of iterations:
|
290
|
+
#
|
291
|
+
# user system total real
|
292
|
+
# 0001 0.000000 0.000000 0.000000 ( 0.000000)
|
293
|
+
# 0010 0.000000 0.000000 0.000000 ( 0.000000)
|
294
|
+
# 0100 0.078000 0.000000 0.078000 ( 0.078000)
|
295
|
+
# 1000 0.641000 0.000000 0.641000 ( 0.641000)
|
296
|
+
# 5000 3.172000 0.015000 3.187000 ( 3.219000)
|
297
|
+
#
|
298
|
+
# Lookup Easter Sunday, without caching, by number of iterations:
|
299
|
+
#
|
300
|
+
# user system total real
|
301
|
+
# 0001 0.000000 0.000000 0.000000 ( 0.000000)
|
302
|
+
# 0010 0.016000 0.000000 0.016000 ( 0.016000)
|
303
|
+
# 0100 0.125000 0.000000 0.125000 ( 0.125000)
|
304
|
+
# 1000 1.234000 0.000000 1.234000 ( 1.234000)
|
305
|
+
# 5000 6.094000 0.031000 6.125000 ( 6.141000)
|
306
|
+
def self.call_proc(function, year) # :nodoc:
|
307
|
+
proc_key = Digest::MD5.hexdigest("#{function.to_s}_#{year.to_s}")
|
308
|
+
@@proc_cache[proc_key] = function.call(year) unless @@proc_cache[proc_key]
|
309
|
+
@@proc_cache[proc_key]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# === Extending Ruby's Date class with the Holidays gem
|
314
|
+
# The Holidays gem automatically extends Ruby's Date class and gives you access
|
315
|
+
# to three new methods: holiday?, #holidays and #calculate_mday.
|
316
|
+
#
|
317
|
+
# ==== Examples
|
318
|
+
# Lookup Canada Day in the <tt>:ca</tt> region
|
319
|
+
# Date.civil(2008,7,1).holiday?(:ca)
|
320
|
+
# => true
|
321
|
+
#
|
322
|
+
# Lookup Canada Day in the <tt>:fr</tt> region
|
323
|
+
# Date.civil(2008,7,1).holiday?(:fr)
|
324
|
+
# => false
|
325
|
+
#
|
326
|
+
# Lookup holidays on North America in January 1.
|
327
|
+
# Date.civil(2008,1,1).holidays(:ca, :mx, :us, :informal, :observed)
|
328
|
+
# => [{:name => 'New Year\'s Day'...}]
|
329
|
+
class Date
|
330
|
+
include Holidays
|
331
|
+
|
332
|
+
# Get holidays on the current date.
|
333
|
+
#
|
334
|
+
# Returns an array of hashes or nil. See Holidays#between for options
|
335
|
+
# and the output format.
|
336
|
+
#
|
337
|
+
# Date.civil('2008-01-01').holidays(:ca_)
|
338
|
+
# => [{:name => 'New Year\'s Day',...}]
|
339
|
+
#
|
340
|
+
# Also available via Holidays#on.
|
341
|
+
def holidays(*options)
|
342
|
+
Holidays.on(self, options)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Check if the current date is a holiday.
|
346
|
+
#
|
347
|
+
# Returns true or false.
|
348
|
+
#
|
349
|
+
# Date.civil('2008-01-01').holiday?(:ca)
|
350
|
+
# => true
|
351
|
+
def holiday?(*options)
|
352
|
+
holidays = self.holidays(options)
|
353
|
+
holidays && !holidays.empty?
|
354
|
+
end
|
355
|
+
|
356
|
+
# Calculate day of the month based on the week number and the day of the
|
357
|
+
# week.
|
358
|
+
#
|
359
|
+
# ==== Parameters
|
360
|
+
# [<tt>year</tt>] Integer.
|
361
|
+
# [<tt>month</tt>] Integer from 1-12.
|
362
|
+
# [<tt>week</tt>] One of <tt>:first</tt>, <tt>:second</tt>, <tt>:third</tt>,
|
363
|
+
# <tt>:fourth</tt>, <tt>:fifth</tt> or <tt>:last</tt>.
|
364
|
+
# [<tt>wday</tt>] Day of the week as an integer from 0 (Sunday) to 6
|
365
|
+
# (Saturday) or as a symbol (e.g. <tt>:monday</tt>).
|
366
|
+
#
|
367
|
+
# Returns an integer.
|
368
|
+
#
|
369
|
+
# ===== Examples
|
370
|
+
# First Monday of January, 2008:
|
371
|
+
# Date.calculate_mday(2008, 1, :first, :monday)
|
372
|
+
# => 7
|
373
|
+
#
|
374
|
+
# Third Thursday of December, 2008:
|
375
|
+
# Date.calculate_mday(2008, 12, :third, :thursday)
|
376
|
+
# => 18
|
377
|
+
#
|
378
|
+
# Last Monday of January, 2008:
|
379
|
+
# Date.calculate_mday(2008, 1, :last, 1)
|
380
|
+
# => 28
|
381
|
+
#--
|
382
|
+
# see http://www.irt.org/articles/js050/index.htm
|
383
|
+
def self.calculate_mday(year, month, week, wday)
|
384
|
+
raise ArgumentError, "Week parameter must be one of Holidays::WEEKS (provided #{week})." unless WEEKS.include?(week) or WEEKS.has_value?(week)
|
385
|
+
|
386
|
+
unless wday.kind_of?(Numeric) and wday.between?(0,6) or DAY_SYMBOLS.index(wday)
|
387
|
+
raise ArgumentError, "Wday parameter must be an integer between 0 and 6 or one of Date::DAY_SYMBOLS."
|
388
|
+
end
|
389
|
+
|
390
|
+
week = WEEKS[week] if week.kind_of?(Symbol)
|
391
|
+
wday = DAY_SYMBOLS.index(wday) if wday.kind_of?(Symbol)
|
392
|
+
|
393
|
+
# :first, :second, :third, :fourth or :fifth
|
394
|
+
if week > 0
|
395
|
+
return ((week - 1) * 7) + 1 + ((7 + wday - Date.civil(year, month,(week-1)*7 + 1).wday) % 7)
|
396
|
+
end
|
397
|
+
|
398
|
+
days = MONTH_LENGTHS[month-1]
|
399
|
+
|
400
|
+
days = 29 if month == 2 and Date.leap?(year)
|
401
|
+
|
402
|
+
return days - ((Date.civil(year, month, days).wday - wday + 7) % 7) - (7 * (week.abs - 1))
|
403
|
+
end
|
404
|
+
end
|