holidays 11.6.0 → 11.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da70f535239a93f75537c181226438b44640775167e06f141e70622f5108ec66
4
- data.tar.gz: 604b4dfc18dfe5e4c031069445c9c7b2261f3459091c04ab9d64e085838b1448
3
+ metadata.gz: a0cce6439fbf9b7dafb577ae8ea715393556a6304fd312ac626c944a1c0ba6da
4
+ data.tar.gz: 9f177f9d50d4c98d74df77f95eed42b3de5f91f1ea52e10c8252ec0f3bf0569f
5
5
  SHA512:
6
- metadata.gz: a66c1b9df1b5f51e90f8905b044bb5d4bbf181f3f8ee6c30e9905e4d61d41145d4500ae618123718f905028808fc4fc6ce6a42855346da91c4213d485d396953
7
- data.tar.gz: b82030d3894bba76b7883bd936b83c726a98b9106b50620c4b19bca40526b1b62854dde49a15fac8f23587582e492a780c5f4512e2a07475a62dafb31cbfaa06
6
+ metadata.gz: 23b54b4312a073ef3eab2ee4eb3948ebd91a9b7e6cf33706a1b3105eeb9b3112660649027fce7b6253d17f6a149954b456ab78aac8b8855a08268b2ed739a6eb
7
+ data.tar.gz: 7cc582e293f9d6b2ce9b5b92c715c2e0294eef6986ac04133be3a75cda4bb7fdd0912739794ce0361ab04d29af968983e1bdd14f777e2c85d39e56eb036a4de6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Ruby Holidays Gem CHANGELOG
2
2
 
3
+ ## 11.7.0
4
+
5
+ * Update to [v9.2.0 definitions](https://github.com/holidays/definitions/releases/tag/v9.2.0): `ma` Eid al-Fitr and Eid al-Adha, `my` Hari Raya Puasa and Hari Raya Haji.
6
+ * Add `ma` Eid al-Fitr and Eid al-Adha, calculated from the Hijri calendar. Years where the date proclaimed by the Ministry of Habous and Islamic Affairs differs from the calculation (Eid al-Fitr 2022, Eid al-Adha 2021) use the proclaimed date. [#510](https://github.com/holidays/holidays/pull/510), [#392](https://github.com/holidays/holidays/issues/392)
7
+ * Add `my` Hari Raya Puasa and Hari Raya Haji, calculated from the Hijri calendar. Years where the gazetted date differs from the calculation use the gazetted date, and a holiday falling on a Sunday is observed on the following Monday. [#511](https://github.com/holidays/holidays/pull/511), [#392](https://github.com/holidays/holidays/issues/392)
8
+ * Fix `next_holidays` returning too few holidays and skipping some. It only searched the 12 months after the start date; it now keeps searching later years until enough holidays are found. [#514](https://github.com/holidays/holidays/pull/514), [#513](https://github.com/holidays/holidays/issues/513)
9
+
3
10
  ## 11.6.0
4
11
 
5
12
  * Update to [v9.1.0 definitions](https://github.com/holidays/definitions/releases/tag/v9.1.0): `tr` feast dates calculated instead of table-driven, `vn` Giỗ Tổ Hùng Vương date fixes, and a region-aware `us` Independence Day observed shift.
@@ -12,7 +12,9 @@ module Holidays
12
12
 
13
13
  def self.holidays_by_month
14
14
  {
15
- 1 => [{:mday => 1, :name => "Ras l' âm", :regions => [:ma]},
15
+ 0 => [{:function => "eid_al_fitr(year)", :function_arguments => [:year], :name => "Eid al-Fitr", :regions => [:ma]},
16
+ {:function => "eid_al_adha(year)", :function_arguments => [:year], :name => "Eid al-Adha", :regions => [:ma]}],
17
+ 1 => [{:mday => 1, :name => "Ras l' âm", :regions => [:ma]},
16
18
  {:mday => 11, :name => "Takdim watikat al-istiqlal", :regions => [:ma]}],
17
19
  5 => [{:mday => 1, :name => "Eid Ash-Shughl", :regions => [:ma]}],
18
20
  7 => [{:mday => 30, :name => "Eid Al-Ârch", :regions => [:ma]}],
@@ -12,7 +12,9 @@ module Holidays
12
12
 
13
13
  def self.holidays_by_month
14
14
  {
15
- 1 => [{:mday => 1, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "New Year's Day", :regions => [:my]}],
15
+ 0 => [{:function => "hari_raya_puasa(year)", :function_arguments => [:year], :observed => "to_monday_if_sunday(date)", :observed_arguments => [:date], :name => "Hari Raya Puasa", :regions => [:my]},
16
+ {:function => "hari_raya_haji(year)", :function_arguments => [:year], :observed => "to_monday_if_sunday(date)", :observed_arguments => [:date], :name => "Hari Raya Haji", :regions => [:my]}],
17
+ 1 => [{:mday => 1, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "New Year's Day", :regions => [:my]}],
16
18
  5 => [{:mday => 1, :name => "Labour Day", :regions => [:my]}],
17
19
  6 => [{:mday => 4, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Agong's Birthday", :regions => [:my]}],
18
20
  8 => [{:mday => 31, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Independence Day", :regions => [:my]}],
@@ -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,12 +48,16 @@ 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,
57
63
  "independence_day(region, date)" => US.method(:independence_day).to_proc,
@@ -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
- # This could be smarter but I don't have any evidence that just checking for
20
- # the next 12 months will cause us issues. If it does we can implement something
21
- # smarter here to check in smaller increments.
22
- dates_driver = @dates_driver_builder.call(from_date, from_date >> 12)
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
- @definition_search
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,3 @@
1
1
  module Holidays
2
- VERSION = '11.6.0'
2
+ VERSION = '11.7.0'
3
3
  end
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.6.0
4
+ version: 11.7.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