holidays 11.6.0 → 11.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +11 -8
- data/lib/generated_definitions/REGIONS.rb +3 -3
- data/lib/generated_definitions/ar.rb +1 -1
- data/lib/generated_definitions/at.rb +1 -1
- data/lib/generated_definitions/au.rb +2 -2
- data/lib/generated_definitions/be_fr.rb +1 -1
- data/lib/generated_definitions/be_nl.rb +1 -1
- data/lib/generated_definitions/bg.rb +1 -1
- data/lib/generated_definitions/br.rb +1 -1
- data/lib/generated_definitions/by.rb +1 -1
- data/lib/generated_definitions/ca.rb +1 -1
- data/lib/generated_definitions/ch.rb +1 -1
- data/lib/generated_definitions/cl.rb +3 -2
- data/lib/generated_definitions/cn.rb +1 -1
- data/lib/generated_definitions/co.rb +1 -1
- data/lib/generated_definitions/cr.rb +1 -1
- data/lib/generated_definitions/cy.rb +1 -1
- data/lib/generated_definitions/cz.rb +1 -1
- data/lib/generated_definitions/de.rb +1 -1
- data/lib/generated_definitions/dk.rb +1 -1
- data/lib/generated_definitions/ecbtarget.rb +1 -1
- data/lib/generated_definitions/ee.rb +1 -1
- data/lib/generated_definitions/es.rb +1 -1
- data/lib/generated_definitions/europe.rb +1 -1
- data/lib/generated_definitions/federalreserve.rb +1 -1
- data/lib/generated_definitions/federalreservebanks.rb +1 -1
- data/lib/generated_definitions/fedex.rb +1 -1
- data/lib/generated_definitions/fi.rb +1 -1
- data/lib/generated_definitions/fr.rb +1 -1
- data/lib/generated_definitions/gb.rb +1 -1
- data/lib/generated_definitions/ge.rb +1 -1
- data/lib/generated_definitions/gr.rb +1 -1
- data/lib/generated_definitions/hk.rb +1 -1
- data/lib/generated_definitions/hr.rb +1 -1
- data/lib/generated_definitions/hu.rb +1 -1
- data/lib/generated_definitions/ie.rb +1 -1
- data/lib/generated_definitions/il.rb +1 -1
- data/lib/generated_definitions/in.rb +1 -1
- data/lib/generated_definitions/is.rb +1 -1
- data/lib/generated_definitions/it.rb +1 -1
- data/lib/generated_definitions/jp.rb +1 -1
- data/lib/generated_definitions/ke.rb +1 -1
- data/lib/generated_definitions/kr.rb +1 -1
- data/lib/generated_definitions/kz.rb +1 -1
- data/lib/generated_definitions/li.rb +1 -1
- data/lib/generated_definitions/lt.rb +1 -1
- data/lib/generated_definitions/lu.rb +1 -1
- data/lib/generated_definitions/lv.rb +1 -1
- data/lib/generated_definitions/ma.rb +3 -1
- data/lib/generated_definitions/mc.rb +1 -1
- data/lib/generated_definitions/mt_en.rb +1 -1
- data/lib/generated_definitions/mt_mt.rb +1 -1
- data/lib/generated_definitions/mx.rb +1 -1
- data/lib/generated_definitions/my.rb +3 -1
- data/lib/generated_definitions/nerc.rb +1 -1
- data/lib/generated_definitions/ng.rb +1 -1
- data/lib/generated_definitions/nl.rb +1 -1
- data/lib/generated_definitions/no.rb +1 -1
- data/lib/generated_definitions/northamerica.rb +4 -3
- data/lib/generated_definitions/nyse.rb +1 -1
- data/lib/generated_definitions/nz.rb +1 -1
- data/lib/generated_definitions/pe.rb +1 -1
- data/lib/generated_definitions/ph.rb +1 -1
- data/lib/generated_definitions/pl.rb +1 -1
- data/lib/generated_definitions/pt.rb +1 -1
- data/lib/generated_definitions/ro.rb +1 -1
- data/lib/generated_definitions/rs_cyrl.rb +1 -1
- data/lib/generated_definitions/rs_la.rb +1 -1
- data/lib/generated_definitions/ru.rb +1 -1
- data/lib/generated_definitions/scandinavia.rb +1 -1
- data/lib/generated_definitions/se.rb +1 -1
- data/lib/generated_definitions/sg.rb +1 -1
- data/lib/generated_definitions/si.rb +1 -1
- data/lib/generated_definitions/sk.rb +1 -1
- data/lib/generated_definitions/southamerica.rb +2 -1
- data/lib/generated_definitions/th.rb +1 -1
- data/lib/generated_definitions/tn.rb +1 -1
- data/lib/generated_definitions/tr.rb +4 -1
- data/lib/generated_definitions/tsx.rb +1 -1
- data/lib/generated_definitions/ua.rb +1 -1
- data/lib/generated_definitions/unitednations.rb +1 -1
- data/lib/generated_definitions/ups.rb +1 -1
- data/lib/generated_definitions/us.rb +4 -3
- data/lib/generated_definitions/ve.rb +1 -1
- data/lib/generated_definitions/vn.rb +1 -1
- data/lib/generated_definitions/za.rb +1 -1
- data/lib/holidays/core_extensions/date.rb +11 -3
- data/lib/holidays/date_calculator/hijri_date.rb +10 -7
- data/lib/holidays/date_calculator/lunar_date.rb +269 -83
- data/lib/holidays/definition/context/generator.rb +27 -2
- data/lib/holidays/definition/custom_methods/cl.rb +8 -0
- data/lib/holidays/definition/custom_methods/cn.rb +7 -1
- data/lib/holidays/definition/custom_methods/ma.rb +48 -0
- data/lib/holidays/definition/custom_methods/my.rb +55 -0
- data/lib/holidays/definition/custom_methods/registry.rb +8 -0
- data/lib/holidays/definition/custom_methods/tr.rb +20 -2
- data/lib/holidays/definition/generator/module.rb +1 -1
- data/lib/holidays/definition/repository/holidays_by_month.rb +2 -1
- data/lib/holidays/errors.rb +5 -0
- data/lib/holidays/finder/context/next_holiday.rb +27 -17
- data/lib/holidays/finder/context/search.rb +67 -23
- data/lib/holidays/finder/context/year_holiday.rb +6 -8
- data/lib/holidays/finder/rules/in_region.rb +19 -14
- data/lib/holidays/version.rb +1 -1
- metadata +3 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
module Holidays
|
|
4
|
+
module Definition
|
|
5
|
+
module CustomMethods
|
|
6
|
+
# ma custom holiday calculations.
|
|
7
|
+
#
|
|
8
|
+
# Eid al-Fitr is 1 Shawwal and Eid al-Adha is 10 Dhul-Hijjah of the
|
|
9
|
+
# Hijri calendar. Both are derived from the arithmetic Islamic calendar
|
|
10
|
+
# (Holidays::DateCalculator::HijriDate). The civil holidays are
|
|
11
|
+
# proclaimed by Morocco's Ministry of Habous and Islamic Affairs and in
|
|
12
|
+
# some years land a day off from the arithmetic result; MINISTRY_OVERRIDES
|
|
13
|
+
# pins those years to the proclaimed date. Years with no entry fall back
|
|
14
|
+
# to the calculation. See holidays#392.
|
|
15
|
+
module MA
|
|
16
|
+
SHAWWAL = 10
|
|
17
|
+
DHU_AL_HIJJAH = 12
|
|
18
|
+
|
|
19
|
+
# Proclaimed first days that differ from the arithmetic calendar,
|
|
20
|
+
# keyed by [feast, gregorian_year]. Sourced from the Ministry of
|
|
21
|
+
# Habous and Islamic Affairs communiques reported via maroc.ma,
|
|
22
|
+
# Hespress, and Morocco World News.
|
|
23
|
+
MINISTRY_OVERRIDES = {
|
|
24
|
+
[:eid_al_fitr, 2022] => Date.new(2022, 5, 2),
|
|
25
|
+
|
|
26
|
+
[:eid_al_adha, 2021] => Date.new(2021, 7, 21),
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
def eid_al_fitr(year)
|
|
31
|
+
feast(:eid_al_fitr, year, SHAWWAL, 1)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def eid_al_adha(year)
|
|
35
|
+
feast(:eid_al_adha, year, DHU_AL_HIJJAH, 10)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def feast(name, year, hijri_month, hijri_day)
|
|
41
|
+
MINISTRY_OVERRIDES[[name, year]] ||
|
|
42
|
+
Holidays::Factory::DateCalculator.hijri_date.gregorian_year_occurrence(year, hijri_month, hijri_day)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
module Holidays
|
|
4
|
+
module Definition
|
|
5
|
+
module CustomMethods
|
|
6
|
+
# my custom holiday calculations.
|
|
7
|
+
#
|
|
8
|
+
# Hari Raya Puasa (Eid al-Fitr) is 1 Shawwal and Hari Raya Haji (Eid
|
|
9
|
+
# al-Adha) is 10 Dhul-Hijjah of the Hijri calendar. Both are derived
|
|
10
|
+
# from the arithmetic Islamic calendar (Holidays::DateCalculator::HijriDate).
|
|
11
|
+
# The civil holidays are fixed by the Yang di-Pertuan Agong (Conference
|
|
12
|
+
# of Rulers) on JAKIM's moon-sighting advice and in some years have
|
|
13
|
+
# landed a day before the arithmetic result; GAZETTE_OVERRIDES pins
|
|
14
|
+
# those years to the gazetted date. Years with no entry fall back to
|
|
15
|
+
# the calculation. See holidays#392.
|
|
16
|
+
module MY
|
|
17
|
+
SHAWWAL = 10
|
|
18
|
+
DHU_AL_HIJJAH = 12
|
|
19
|
+
|
|
20
|
+
# Gazetted first days that differ from the arithmetic calendar,
|
|
21
|
+
# keyed by [feast, gregorian_year]. Sourced from the official
|
|
22
|
+
# Malaysian public holiday gazette, cross-checked against
|
|
23
|
+
# definitions/sg.yaml (agrees in every overlapping year 2017-2026).
|
|
24
|
+
GAZETTE_OVERRIDES = {
|
|
25
|
+
[:hari_raya_puasa, 2014] => Date.new(2014, 7, 28),
|
|
26
|
+
[:hari_raya_puasa, 2015] => Date.new(2015, 7, 17),
|
|
27
|
+
[:hari_raya_puasa, 2016] => Date.new(2016, 7, 6),
|
|
28
|
+
[:hari_raya_puasa, 2017] => Date.new(2017, 6, 25),
|
|
29
|
+
[:hari_raya_puasa, 2026] => Date.new(2026, 3, 21),
|
|
30
|
+
|
|
31
|
+
[:hari_raya_haji, 2016] => Date.new(2016, 9, 12),
|
|
32
|
+
[:hari_raya_haji, 2017] => Date.new(2017, 9, 1),
|
|
33
|
+
[:hari_raya_haji, 2019] => Date.new(2019, 8, 11),
|
|
34
|
+
}.freeze
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
def hari_raya_puasa(year)
|
|
38
|
+
feast(:hari_raya_puasa, year, SHAWWAL, 1)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def hari_raya_haji(year)
|
|
42
|
+
feast(:hari_raya_haji, year, DHU_AL_HIJJAH, 10)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def feast(name, year, hijri_month, hijri_day)
|
|
48
|
+
GAZETTE_OVERRIDES[[name, year]] ||
|
|
49
|
+
Holidays::Factory::DateCalculator.hijri_date.gregorian_year_occurrence(year, hijri_month, hijri_day)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -13,6 +13,8 @@ require 'holidays/definition/custom_methods/is'
|
|
|
13
13
|
require 'holidays/definition/custom_methods/jp'
|
|
14
14
|
require 'holidays/definition/custom_methods/kr'
|
|
15
15
|
require 'holidays/definition/custom_methods/lv'
|
|
16
|
+
require 'holidays/definition/custom_methods/ma'
|
|
17
|
+
require 'holidays/definition/custom_methods/my'
|
|
16
18
|
require 'holidays/definition/custom_methods/nz'
|
|
17
19
|
require 'holidays/definition/custom_methods/ph'
|
|
18
20
|
require 'holidays/definition/custom_methods/se'
|
|
@@ -46,14 +48,19 @@ module Holidays
|
|
|
46
48
|
"columbus_day_cl(year)" => CL.method(:columbus_day_cl).to_proc,
|
|
47
49
|
"day_after_thanksgiving(year)" => FEDEX.method(:day_after_thanksgiving).to_proc,
|
|
48
50
|
"de_buss_und_bettag(year)" => DE.method(:de_buss_und_bettag).to_proc,
|
|
51
|
+
"eid_al_adha(year)" => MA.method(:eid_al_adha).to_proc,
|
|
52
|
+
"eid_al_fitr(year)" => MA.method(:eid_al_fitr).to_proc,
|
|
49
53
|
"election_day(year)" => US.method(:election_day).to_proc,
|
|
50
54
|
"even_year_election_day(year)" => US.method(:even_year_election_day).to_proc,
|
|
51
55
|
"fi_juhannusaatto(year)" => FI.method(:fi_juhannusaatto).to_proc,
|
|
52
56
|
"fi_juhannuspaiva(year)" => FI.method(:fi_juhannuspaiva).to_proc,
|
|
53
57
|
"fi_pyhainpaiva(year)" => FI.method(:fi_pyhainpaiva).to_proc,
|
|
54
58
|
"georgia_state_holiday(year, month)" => US.method(:georgia_state_holiday).to_proc,
|
|
59
|
+
"hari_raya_haji(year)" => MY.method(:hari_raya_haji).to_proc,
|
|
60
|
+
"hari_raya_puasa(year)" => MY.method(:hari_raya_puasa).to_proc,
|
|
55
61
|
"hobart_show_day(year)" => AU.method(:hobart_show_day).to_proc,
|
|
56
62
|
"ie_st_brigids_day(year)" => IE.method(:ie_st_brigids_day).to_proc,
|
|
63
|
+
"indigenous_peoples_day_cl(year)" => CL.method(:indigenous_peoples_day_cl).to_proc,
|
|
57
64
|
"independence_day(region, date)" => US.method(:independence_day).to_proc,
|
|
58
65
|
"is_sumardagurinn_fyrsti(year)" => IS.method(:is_sumardagurinn_fyrsti).to_proc,
|
|
59
66
|
"jp_citizens_holiday(year)" => JP.method(:jp_citizens_holiday).to_proc,
|
|
@@ -87,6 +94,7 @@ module Holidays
|
|
|
87
94
|
"qld_queens_bday_october(year)" => AU.method(:qld_queens_bday_october).to_proc,
|
|
88
95
|
"qld_queens_birthday_june(year)" => AU.method(:qld_queens_birthday_june).to_proc,
|
|
89
96
|
"ramadan_feast(year)" => TR.method(:ramadan_feast).to_proc,
|
|
97
|
+
"ramadan_feast_second_in_year(year)" => TR.method(:ramadan_feast_second_in_year).to_proc,
|
|
90
98
|
"rosh_hashanah(year)" => US.method(:rosh_hashanah).to_proc,
|
|
91
99
|
"sacrifice_feast(year)" => TR.method(:sacrifice_feast).to_proc,
|
|
92
100
|
"se_alla_helgons_dag(year)" => SE.method(:se_alla_helgons_dag).to_proc,
|
|
@@ -12,6 +12,10 @@ module Holidays
|
|
|
12
12
|
# day (2016 Ramazan Bayramı, two days) before the arithmetic result;
|
|
13
13
|
# DIYANET_OVERRIDES pins those years to the proclaimed date. Years with
|
|
14
14
|
# no entry fall back to the calculation. See definitions#377.
|
|
15
|
+
#
|
|
16
|
+
# ramadan_feast only returns the first occurrence of a Gregorian year;
|
|
17
|
+
# ramadan_feast_second_in_year returns the second one in the rare years
|
|
18
|
+
# that have two (2033), and nil otherwise.
|
|
15
19
|
module TR
|
|
16
20
|
SHAWWAL = 10
|
|
17
21
|
DHU_AL_HIJJAH = 12
|
|
@@ -19,7 +23,7 @@ module Holidays
|
|
|
19
23
|
# Proclaimed first days that differ from the arithmetic calendar,
|
|
20
24
|
# keyed by [feast, gregorian_year]. Sourced from the Diyanet dates
|
|
21
25
|
# that the definition file previously carried as a fixed table, plus
|
|
22
|
-
# https://vakithesaplama.diyanet.gov.tr/resmitatiller.php for 2021-
|
|
26
|
+
# https://vakithesaplama.diyanet.gov.tr/resmitatiller.php for 2021-2035.
|
|
23
27
|
DIYANET_OVERRIDES = {
|
|
24
28
|
[:ramadan_feast, 2014] => Date.new(2014, 7, 28),
|
|
25
29
|
[:ramadan_feast, 2015] => Date.new(2015, 7, 17),
|
|
@@ -32,6 +36,9 @@ module Holidays
|
|
|
32
36
|
[:ramadan_feast, 2027] => Date.new(2027, 3, 9),
|
|
33
37
|
[:ramadan_feast, 2028] => Date.new(2028, 2, 26),
|
|
34
38
|
[:ramadan_feast, 2030] => Date.new(2030, 2, 4),
|
|
39
|
+
[:ramadan_feast, 2031] => Date.new(2031, 1, 24),
|
|
40
|
+
[:ramadan_feast, 2033] => Date.new(2033, 1, 2),
|
|
41
|
+
[:ramadan_feast, 2035] => Date.new(2035, 12, 1),
|
|
35
42
|
|
|
36
43
|
[:sacrifice_feast, 2014] => Date.new(2014, 10, 4),
|
|
37
44
|
[:sacrifice_feast, 2016] => Date.new(2016, 9, 12),
|
|
@@ -44,6 +51,8 @@ module Holidays
|
|
|
44
51
|
[:sacrifice_feast, 2025] => Date.new(2025, 6, 6),
|
|
45
52
|
[:sacrifice_feast, 2027] => Date.new(2027, 5, 16),
|
|
46
53
|
[:sacrifice_feast, 2030] => Date.new(2030, 4, 13),
|
|
54
|
+
[:sacrifice_feast, 2031] => Date.new(2031, 4, 2),
|
|
55
|
+
[:sacrifice_feast, 2033] => Date.new(2033, 3, 11),
|
|
47
56
|
}.freeze
|
|
48
57
|
|
|
49
58
|
class << self
|
|
@@ -51,6 +60,11 @@ module Holidays
|
|
|
51
60
|
feast(:ramadan_feast, year, SHAWWAL, 1)
|
|
52
61
|
end
|
|
53
62
|
|
|
63
|
+
def ramadan_feast_second_in_year(year)
|
|
64
|
+
occurrences = hijri.gregorian_year_occurrences(year, SHAWWAL, 1)
|
|
65
|
+
occurrences.last if occurrences.size > 1
|
|
66
|
+
end
|
|
67
|
+
|
|
54
68
|
def sacrifice_feast(year)
|
|
55
69
|
feast(:sacrifice_feast, year, DHU_AL_HIJJAH, 10)
|
|
56
70
|
end
|
|
@@ -59,7 +73,11 @@ module Holidays
|
|
|
59
73
|
|
|
60
74
|
def feast(name, year, hijri_month, hijri_day)
|
|
61
75
|
DIYANET_OVERRIDES[[name, year]] ||
|
|
62
|
-
|
|
76
|
+
hijri.gregorian_year_occurrence(year, hijri_month, hijri_day)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def hijri
|
|
80
|
+
Holidays::Factory::DateCalculator.hijri_date
|
|
63
81
|
end
|
|
64
82
|
end
|
|
65
83
|
end
|
|
@@ -49,7 +49,8 @@ module Holidays
|
|
|
49
49
|
existing_def[:function_modifier] == target_def[:function_modifier] &&
|
|
50
50
|
existing_def[:type] == target_def[:type] &&
|
|
51
51
|
existing_def[:observed] == target_def[:observed] &&
|
|
52
|
-
existing_def[:year_ranges] == target_def[:year_ranges]
|
|
52
|
+
existing_def[:year_ranges] == target_def[:year_ranges] &&
|
|
53
|
+
existing_def[:excluded_regions] == target_def[:excluded_regions]
|
|
53
54
|
end
|
|
54
55
|
end
|
|
55
56
|
end
|
data/lib/holidays/errors.rb
CHANGED
|
@@ -8,4 +8,9 @@ module Holidays
|
|
|
8
8
|
class InvalidRegion < Error; end
|
|
9
9
|
|
|
10
10
|
class DefinitionTestError < Error; end
|
|
11
|
+
|
|
12
|
+
# Raised when a calculation needs data for a year outside the range its
|
|
13
|
+
# tables or formula support, e.g. a lunar date past the end of the lunar
|
|
14
|
+
# calendar tables.
|
|
15
|
+
class UnsupportedYearError < Error; end
|
|
11
16
|
end
|
|
@@ -2,6 +2,11 @@ module Holidays
|
|
|
2
2
|
module Finder
|
|
3
3
|
module Context
|
|
4
4
|
class NextHoliday
|
|
5
|
+
# Holidays are searched one 12 month window at a time. The search widens until
|
|
6
|
+
# enough holidays are found or this many years have been searched, which stops
|
|
7
|
+
# a region with no upcoming holidays from being searched forever.
|
|
8
|
+
MAX_YEARS = 50
|
|
9
|
+
|
|
5
10
|
def initialize(definition_search, dates_driver_builder, options_parser)
|
|
6
11
|
@definition_search = definition_search
|
|
7
12
|
@dates_driver_builder = dates_driver_builder
|
|
@@ -12,31 +17,36 @@ module Holidays
|
|
|
12
17
|
validate!(holidays_count, from_date)
|
|
13
18
|
|
|
14
19
|
regions, observed, informal = @options_parser.call(options)
|
|
20
|
+
opts = gather_options(observed, informal)
|
|
15
21
|
|
|
16
22
|
holidays = []
|
|
17
|
-
opts = gather_options(observed, informal)
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
1.upto(MAX_YEARS) do |year|
|
|
25
|
+
holidays.concat(search_window(from_date, year, regions, opts))
|
|
26
|
+
break if holidays.size >= holidays_count
|
|
27
|
+
end
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
.call(dates_driver, regions, opts)
|
|
26
|
-
.sort_by { |a| a[:date] }
|
|
27
|
-
.each do |holiday|
|
|
28
|
-
if holiday[:date] >= from_date
|
|
29
|
-
holidays << holiday
|
|
30
|
-
holidays_count -= 1
|
|
31
|
-
break if holidays_count == 0
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
holidays.sort_by { |a| a[:date] }
|
|
29
|
+
holidays.first(holidays_count)
|
|
36
30
|
end
|
|
37
31
|
|
|
38
32
|
private
|
|
39
33
|
|
|
34
|
+
# Windows are contiguous: each starts the day after the previous one ended. The
|
|
35
|
+
# search only looks at the months around a window (plus month 0, which covers the
|
|
36
|
+
# whole year), so dates past the window end are incomplete. They are discarded here
|
|
37
|
+
# and found by the next window instead.
|
|
38
|
+
def search_window(from_date, year, regions, opts)
|
|
39
|
+
window_start = year == 1 ? from_date : (from_date >> 12 * (year - 1)) + 1
|
|
40
|
+
window_end = from_date >> 12 * year
|
|
41
|
+
|
|
42
|
+
dates_driver = @dates_driver_builder.call(window_start, window_end)
|
|
43
|
+
|
|
44
|
+
@definition_search
|
|
45
|
+
.call(dates_driver, regions, opts)
|
|
46
|
+
.select { |holiday| (window_start..window_end).cover?(holiday[:date]) }
|
|
47
|
+
.sort_by { |holiday| holiday[:date] }
|
|
48
|
+
end
|
|
49
|
+
|
|
40
50
|
def validate!(holidays_count, from_date)
|
|
41
51
|
raise ArgumentError unless holidays_count
|
|
42
52
|
raise ArgumentError if holidays_count <= 0
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'holidays/errors'
|
|
2
|
+
|
|
1
3
|
module Holidays
|
|
2
4
|
module Finder
|
|
3
5
|
module Context
|
|
@@ -14,29 +16,11 @@ module Holidays
|
|
|
14
16
|
|
|
15
17
|
holidays = []
|
|
16
18
|
dates_driver.each do |year, months|
|
|
17
|
-
months.each do |month|
|
|
18
|
-
next unless
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if h[:year_ranges]
|
|
24
|
-
next unless @rules[:year_range].call(year, h[:year_ranges])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
dates = if h[:function]
|
|
28
|
-
custom_holidays(year, month, h, regions)
|
|
29
|
-
else
|
|
30
|
-
date = build_date(year, month, h, regions)
|
|
31
|
-
date ? [date] : []
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
dates.each do |d|
|
|
35
|
-
if observed_set?(options) && h[:observed]
|
|
36
|
-
d = build_observed_date(d, regions, h)
|
|
37
|
-
end
|
|
38
|
-
holidays << {:date => d, :name => h[:name], :regions => h[:regions]}
|
|
39
|
-
end
|
|
19
|
+
candidates(months).each do |month, h|
|
|
20
|
+
next unless applicable?(year, h, regions, options)
|
|
21
|
+
|
|
22
|
+
year_dates(year, months, month, h, regions, options).each do |d|
|
|
23
|
+
holidays << {:date => d, :name => h[:name], :regions => h[:regions]}
|
|
40
24
|
end
|
|
41
25
|
end
|
|
42
26
|
end
|
|
@@ -61,6 +45,66 @@ module Holidays
|
|
|
61
45
|
end
|
|
62
46
|
end
|
|
63
47
|
|
|
48
|
+
# Returns [month, definition] pairs to evaluate for one year of the dates
|
|
49
|
+
# driver. Fixed-date definitions only matter in the driver's months, but a
|
|
50
|
+
# function (e.g. a lunar date filed under its lunar month) can land several
|
|
51
|
+
# months away from the month it is filed under, so every function definition
|
|
52
|
+
# is evaluated, once, regardless of its month.
|
|
53
|
+
# See https://github.com/holidays/holidays/issues/519
|
|
54
|
+
def candidates(months)
|
|
55
|
+
by_month = @holidays_by_month_repo.all
|
|
56
|
+
|
|
57
|
+
in_driver = months.flat_map do |month|
|
|
58
|
+
(by_month[month] || []).map { |h| [month, h] }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
outside_driver = (by_month.keys - months).sort.flat_map do |month|
|
|
62
|
+
by_month[month].select { |h| h[:function] }.map { |h| [month, h] }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
in_driver + outside_driver
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# A year that only pads the query with a border month (see
|
|
69
|
+
# DatesDriverBuilder#add_border_months) may lie past the data a
|
|
70
|
+
# calculation supports, e.g. lunar year 2101. Dates of such a year are
|
|
71
|
+
# outside the query anyway, so they are skipped rather than failing
|
|
72
|
+
# the query. A year the query actually covers still raises.
|
|
73
|
+
def year_dates(year, months, month, h, regions, options)
|
|
74
|
+
holiday_dates(year, month, h, regions, options)
|
|
75
|
+
rescue Holidays::UnsupportedYearError
|
|
76
|
+
raise unless border_padding?(months)
|
|
77
|
+
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Every date in the query adds its own month and a neighbouring one to
|
|
82
|
+
# its year, so a year holding a single month (besides the variable
|
|
83
|
+
# month 0) is only there as border padding.
|
|
84
|
+
def border_padding?(months)
|
|
85
|
+
(months - [0]).size == 1
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def applicable?(year, h, regions, options)
|
|
89
|
+
return false if informal_type?(h[:type]) && !informal_set?(options)
|
|
90
|
+
return false unless @rules[:in_region].call(regions, h[:regions], h[:excluded_regions])
|
|
91
|
+
return true unless h[:year_ranges]
|
|
92
|
+
|
|
93
|
+
@rules[:year_range].call(year, h[:year_ranges])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def holiday_dates(year, month, h, regions, options)
|
|
97
|
+
dates = if h[:function]
|
|
98
|
+
custom_holidays(year, month, h, regions)
|
|
99
|
+
else
|
|
100
|
+
[build_date(year, month, h, regions)].compact
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
return dates unless observed_set?(options) && h[:observed]
|
|
104
|
+
|
|
105
|
+
dates.map { |d| build_observed_date(d, regions, h) }
|
|
106
|
+
end
|
|
107
|
+
|
|
64
108
|
def informal_type?(type)
|
|
65
109
|
type && [:informal, 'informal'].include?(type)
|
|
66
110
|
end
|
|
@@ -13,15 +13,13 @@ module Holidays
|
|
|
13
13
|
|
|
14
14
|
regions, observed, informal = @options_parser.call(options)
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
# the next
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# This is matching what was in holidays.rb currently so I'm keeping it. -pp
|
|
22
|
-
dates_driver = @dates_driver_builder.call(from_date, from_date >> 12)
|
|
23
|
-
|
|
16
|
+
# The driver stops at to_date; the dates driver still adds January of
|
|
17
|
+
# the next year as a border month. Searching a full 12 months from
|
|
18
|
+
# from_date would make the next year a searched year rather than
|
|
19
|
+
# border padding, so e.g. year_holidays for 2100 would need lunar
|
|
20
|
+
# data for 2101.
|
|
24
21
|
to_date = Date.civil(from_date.year, 12, 31)
|
|
22
|
+
dates_driver = @dates_driver_builder.call(from_date, to_date)
|
|
25
23
|
holidays = []
|
|
26
24
|
ret_holidays = []
|
|
27
25
|
opts = gather_options(observed, informal)
|
|
@@ -3,26 +3,31 @@ module Holidays
|
|
|
3
3
|
module Rules
|
|
4
4
|
class InRegion
|
|
5
5
|
class << self
|
|
6
|
-
|
|
6
|
+
# Each requested region is checked on its own. It qualifies when one
|
|
7
|
+
# of the available regions is the region itself or one of its
|
|
8
|
+
# ancestors (us for us_ca) and none of the excluded regions is. The
|
|
9
|
+
# rule matches when any requested region qualifies. :any always
|
|
10
|
+
# matches, whatever is excluded.
|
|
11
|
+
def call(requested, available, excluded = nil)
|
|
7
12
|
return true if requested.include?(:any)
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
# symbol and check for both.
|
|
11
|
-
requested = requested.collect do |r|
|
|
12
|
-
if r.to_s.include?('_')
|
|
13
|
-
chunks = r.to_s.split('_')
|
|
14
|
+
excluded ||= []
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
r
|
|
20
|
-
end
|
|
16
|
+
requested.any? do |region|
|
|
17
|
+
lineage = lineage(region)
|
|
18
|
+
|
|
19
|
+
(available & lineage).any? && (excluded & lineage).empty?
|
|
21
20
|
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
# The region and all of its parents, e.g. :us_ca_xx gives
|
|
26
|
+
# [:us, :us_ca, :us_ca_xx].
|
|
27
|
+
def lineage(region)
|
|
28
|
+
chunks = region.to_s.split('_')
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
1.upto(chunks.length).map { |n| chunks.first(n).join('_').to_sym }
|
|
26
31
|
end
|
|
27
32
|
end
|
|
28
33
|
end
|
data/lib/holidays/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: holidays
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 11.
|
|
4
|
+
version: 11.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Dunae
|
|
@@ -219,6 +219,8 @@ files:
|
|
|
219
219
|
- lib/holidays/definition/custom_methods/jp.rb
|
|
220
220
|
- lib/holidays/definition/custom_methods/kr.rb
|
|
221
221
|
- lib/holidays/definition/custom_methods/lv.rb
|
|
222
|
+
- lib/holidays/definition/custom_methods/ma.rb
|
|
223
|
+
- lib/holidays/definition/custom_methods/my.rb
|
|
222
224
|
- lib/holidays/definition/custom_methods/nz.rb
|
|
223
225
|
- lib/holidays/definition/custom_methods/ph.rb
|
|
224
226
|
- lib/holidays/definition/custom_methods/registry.rb
|