holidays 11.5.0 → 11.6.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: 450c972e94224caf8a44edc3865c9d7246aa7a0f0ac16c5d41156ff2ca460741
4
- data.tar.gz: 2a17f504696cdf7f345fb75b2b715f24f34218c132bb50d61265c8556475aee5
3
+ metadata.gz: da70f535239a93f75537c181226438b44640775167e06f141e70622f5108ec66
4
+ data.tar.gz: 604b4dfc18dfe5e4c031069445c9c7b2261f3459091c04ab9d64e085838b1448
5
5
  SHA512:
6
- metadata.gz: 1379f15a3ad2d6f06278d7e3806007145a58e78dadbaba0395aabc44bde996f36fc76b088be197a2101d7088b6b1107b924ed8fc850bbe91327e9c7a7bdeb947
7
- data.tar.gz: 2cce27a209357ec151b8048cdf2c5a6b532b4613693c52673d489d9c9604fe03394d8c2abb911939ecb44dafac2dfa63eb7cd2b29cd96bc113864868e9285ddf
6
+ metadata.gz: a66c1b9df1b5f51e90f8905b044bb5d4bbf181f3f8ee6c30e9905e4d61d41145d4500ae618123718f905028808fc4fc6ce6a42855346da91c4213d485d396953
7
+ data.tar.gz: b82030d3894bba76b7883bd936b83c726a98b9106b50620c4b19bca40526b1b62854dde49a15fac8f23587582e492a780c5f4512e2a07475a62dafb31cbfaa06
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Ruby Holidays Gem CHANGELOG
2
2
 
3
+ ## 11.6.0
4
+
5
+ * 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.
6
+ * Calculate `tr` Ramazan Bayramı and Kurban Bayramı from a Hijri calendar instead of a hand-maintained per-year table, so they no longer silently disappear past 2030. [#504](https://github.com/holidays/holidays/pull/504)
7
+ * Fix `vn` Giỗ Tổ Hùng Vương dates for 2018-2023, caused by a lunar calendar leap-month bug in the 2017 table row. [#506](https://github.com/holidays/holidays/pull/506)
8
+ * Add a region-aware `independence_day` observed method for `us` Independence Day, replacing the `us_va`-only shift. Most regions shift to the nearest weekday, `us_ri` shifts to the following Monday, and `us_tx` never shifts. [#508](https://github.com/holidays/holidays/pull/508)
9
+
3
10
  ## 11.5.0
4
11
 
5
12
  * Update to [v9.0.0 definitions](https://github.com/holidays/definitions/releases/tag/v9.0.0): new `cn` region; `jp`, `kr`, `nz_sl`, `nz_hb`, `ro` date fixes; `tr` feasts through 2030; `de_be` 2025; informal Day of the Dead for `us`/`ca`. The v9.0.0 major is a definitions format change only and does not affect gem results or API.
data/README.md CHANGED
@@ -20,6 +20,7 @@ This gem is tested with the following ruby versions:
20
20
  * 3.4
21
21
  * 4.0
22
22
  * JRuby 10.0.5.0
23
+ * JRuby 10.1.0.0
23
24
 
24
25
  ## Semver
25
26
 
@@ -83,8 +83,7 @@ module Holidays
83
83
  {:mday => 12, :type => :informal, :name => "Orangemen's Day", :regions => [:ca_nl]},
84
84
  {:mday => 9, :year_ranges => { :from => 2020 },:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Nunavut Day", :regions => [:ca_nu]},
85
85
  {:mday => 3, :name => "Emancipation Day", :regions => [:us_vi]},
86
- {:mday => 4, :name => "Independence Day", :regions => [:us]},
87
- {:mday => 4, :function => "to_weekday_if_weekend(date)", :function_arguments => [:date], :name => "Independence Day (Holiday)", :regions => [:us_va]},
86
+ {:mday => 4, :observed => "independence_day(region, date)", :observed_arguments => [:region, :date], :name => "Independence Day", :regions => [:us]},
88
87
  {:mday => 24, :name => "Pioneer Day", :regions => [:us_ut]}],
89
88
  8 => [{:wday => 1, :week => 1, :name => "B.C. Day", :regions => [:ca_bc]},
90
89
  {:wday => 1, :week => 1, :name => "Saskatchewan Day", :regions => [:ca_sk]},
@@ -58,8 +58,7 @@ module Holidays
58
58
  {:mday => 20, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "West Virginia Day", :regions => [:us_wv]},
59
59
  {:wday => 0, :week => 3, :type => :informal, :name => "Father's Day", :regions => [:us, :ca]}],
60
60
  7 => [{:mday => 3, :name => "Emancipation Day", :regions => [:us_vi]},
61
- {:mday => 4, :name => "Independence Day", :regions => [:us]},
62
- {:mday => 4, :function => "to_weekday_if_weekend(date)", :function_arguments => [:date], :name => "Independence Day (Holiday)", :regions => [:us_va]},
61
+ {:mday => 4, :observed => "independence_day(region, date)", :observed_arguments => [:region, :date], :name => "Independence Day", :regions => [:us]},
63
62
  {:mday => 24, :name => "Pioneer Day", :regions => [:us_ut]}],
64
63
  8 => [{:wday => 1, :week => 2, :name => "Victory Day", :regions => [:us_ri]},
65
64
  {:mday => 16, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Bennington Battle Day", :regions => [:us_vt]},
@@ -0,0 +1,52 @@
1
+ require 'date'
2
+
3
+ module Holidays
4
+ module DateCalculator
5
+ # Arithmetic ("tabular", a.k.a. Kuwaiti) Islamic calendar.
6
+ #
7
+ # Months alternate 30 and 29 days; leap years add a day to the twelfth
8
+ # month on a fixed 11-of-30 cycle. This is a purely arithmetic calendar,
9
+ # so it can land a day (occasionally two) either side of a locally
10
+ # proclaimed date. Callers that need the proclaimed date layer their own
11
+ # override table on top of this (see
12
+ # Holidays::Definition::CustomMethods::TR).
13
+ class HijriDate
14
+ # Julian day number of 1 Muharram 1 AH minus one day, chosen so that
15
+ # to_jd's month/day terms are added directly. Corresponds to the civil
16
+ # epoch (Friday, 16 July 622 CE proleptic Julian).
17
+ EPOCH_JDN = 1948439
18
+
19
+ def to_gregorian(hijri_year, hijri_month, hijri_day)
20
+ Date.jd(to_jd(hijri_year, hijri_month, hijri_day))
21
+ end
22
+
23
+ # Given a Gregorian year and a fixed Hijri month/day, return the
24
+ # occurrence that falls within that Gregorian year, or nil if none does.
25
+ #
26
+ # A fixed Hijri date drifts ~11 days earlier each Gregorian year, so
27
+ # roughly once every 33 years it falls twice in the same Gregorian year
28
+ # (once in early January, once in late December). Only the earlier
29
+ # occurrence is returned.
30
+ def gregorian_year_occurrence(gregorian_year, hijri_month, hijri_day)
31
+ candidate_hijri_year = gregorian_year - 579
32
+
33
+ (candidate_hijri_year - 1..candidate_hijri_year + 1).each do |hijri_year|
34
+ date = to_gregorian(hijri_year, hijri_month, hijri_day)
35
+ return date if date.year == gregorian_year
36
+ end
37
+
38
+ nil
39
+ end
40
+
41
+ private
42
+
43
+ def to_jd(year, month, day)
44
+ day +
45
+ (29.5 * (month - 1)).ceil +
46
+ (year - 1) * 354 +
47
+ (3 + 11 * year) / 30 +
48
+ EPOCH_JDN
49
+ end
50
+ end
51
+ end
52
+ end
@@ -152,7 +152,7 @@ module Holidays
152
152
  [384, 1, 2, 1, 2, 1, 2, 1, 2, 4, 2, 1, 2].freeze,
153
153
  [354, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1].freeze,
154
154
  [355, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2].freeze,
155
- [355, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2].freeze,
155
+ [384, 1, 2, 1, 2, 1, 5, 1, 2, 1, 2, 2, 2].freeze, # 2017 has a leap 6th month; previous entry omitted it, shifting every later date
156
156
  [354, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2].freeze,
157
157
  [354, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2].freeze,
158
158
  [384, 2, 1, 2, 4, 2, 1, 1, 2, 1, 2, 1, 2].freeze,
@@ -3,10 +3,12 @@ module Holidays
3
3
  module Context
4
4
  # Merge a new set of definitions into the Holidays module.
5
5
  class Merger
6
- def initialize(holidays_by_month_repo, regions_repo, custom_methods_repo)
6
+ def initialize(holidays_by_month_repo, regions_repo, custom_methods_repo, cache_repo, proc_result_cache_repo)
7
7
  @holidays_repo = holidays_by_month_repo
8
8
  @regions_repo = regions_repo
9
9
  @custom_methods_repo = custom_methods_repo
10
+ @cache_repo = cache_repo
11
+ @proc_result_cache_repo = proc_result_cache_repo
10
12
  end
11
13
 
12
14
  def call(target_regions, target_holidays, target_custom_methods, target_custom_method_sources = {})
@@ -17,6 +19,9 @@ module Holidays
17
19
  target_custom_method_sources,
18
20
  derive_function_regions(target_holidays),
19
21
  )
22
+ ensure
23
+ @cache_repo.reset!
24
+ @proc_result_cache_repo.reset!
20
25
  end
21
26
 
22
27
  private
@@ -54,6 +54,7 @@ module Holidays
54
54
  "georgia_state_holiday(year, month)" => US.method(:georgia_state_holiday).to_proc,
55
55
  "hobart_show_day(year)" => AU.method(:hobart_show_day).to_proc,
56
56
  "ie_st_brigids_day(year)" => IE.method(:ie_st_brigids_day).to_proc,
57
+ "independence_day(region, date)" => US.method(:independence_day).to_proc,
57
58
  "is_sumardagurinn_fyrsti(year)" => IS.method(:is_sumardagurinn_fyrsti).to_proc,
58
59
  "jp_citizens_holiday(year)" => JP.method(:jp_citizens_holiday).to_proc,
59
60
  "jp_health_sports_day_substitute(year)" => JP.method(:jp_health_sports_day_substitute).to_proc,
@@ -3,54 +3,63 @@ require 'date'
3
3
  module Holidays
4
4
  module Definition
5
5
  module CustomMethods
6
- # tr custom holiday calculations, ported verbatim from the
7
- # +methods:+ block in definitions/tr.yaml.
6
+ # tr custom holiday calculations.
7
+ #
8
+ # Ramazan Bayramı is 1 Shawwal and Kurban Bayramı is 10 Dhul-Hijjah of
9
+ # the Hijri calendar. Both are derived from the arithmetic Islamic
10
+ # calendar (Holidays::DateCalculator::HijriDate). The civil holidays are
11
+ # proclaimed by Türkiye's Diyanet and in most years so far have landed a
12
+ # day (2016 Ramazan Bayramı, two days) before the arithmetic result;
13
+ # DIYANET_OVERRIDES pins those years to the proclaimed date. Years with
14
+ # no entry fall back to the calculation. See definitions#377.
8
15
  module TR
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 Diyanet dates
21
+ # that the definition file previously carried as a fixed table, plus
22
+ # https://vakithesaplama.diyanet.gov.tr/resmitatiller.php for 2021-2030.
23
+ DIYANET_OVERRIDES = {
24
+ [:ramadan_feast, 2014] => Date.new(2014, 7, 28),
25
+ [:ramadan_feast, 2015] => Date.new(2015, 7, 17),
26
+ [:ramadan_feast, 2016] => Date.new(2016, 7, 5),
27
+ [:ramadan_feast, 2017] => Date.new(2017, 6, 25),
28
+ [:ramadan_feast, 2019] => Date.new(2019, 6, 4),
29
+ [:ramadan_feast, 2022] => Date.new(2022, 5, 2),
30
+ [:ramadan_feast, 2023] => Date.new(2023, 4, 21),
31
+ [:ramadan_feast, 2025] => Date.new(2025, 3, 30),
32
+ [:ramadan_feast, 2027] => Date.new(2027, 3, 9),
33
+ [:ramadan_feast, 2028] => Date.new(2028, 2, 26),
34
+ [:ramadan_feast, 2030] => Date.new(2030, 2, 4),
35
+
36
+ [:sacrifice_feast, 2014] => Date.new(2014, 10, 4),
37
+ [:sacrifice_feast, 2016] => Date.new(2016, 9, 12),
38
+ [:sacrifice_feast, 2017] => Date.new(2017, 9, 1),
39
+ [:sacrifice_feast, 2018] => Date.new(2018, 8, 21),
40
+ [:sacrifice_feast, 2019] => Date.new(2019, 8, 11),
41
+ [:sacrifice_feast, 2022] => Date.new(2022, 7, 9),
42
+ [:sacrifice_feast, 2023] => Date.new(2023, 6, 28),
43
+ [:sacrifice_feast, 2024] => Date.new(2024, 6, 16),
44
+ [:sacrifice_feast, 2025] => Date.new(2025, 6, 6),
45
+ [:sacrifice_feast, 2027] => Date.new(2027, 5, 16),
46
+ [:sacrifice_feast, 2030] => Date.new(2030, 4, 13),
47
+ }.freeze
48
+
9
49
  class << self
10
50
  def ramadan_feast(year)
11
- begin_of_ramadan_feast = {
12
- '2014' => Date.civil(2014, 7, 28),
13
- '2015' => Date.civil(2015, 7, 17),
14
- '2016' => Date.civil(2016, 7, 5),
15
- '2017' => Date.civil(2017, 6, 25),
16
- '2018' => Date.civil(2018, 6, 15),
17
- '2019' => Date.civil(2019, 6, 4),
18
- '2020' => Date.civil(2020, 5, 24),
19
- '2021' => Date.civil(2021, 5, 13),
20
- '2022' => Date.civil(2022, 5, 2),
21
- '2023' => Date.civil(2023, 4, 21),
22
- '2024' => Date.civil(2024, 4, 10),
23
- '2025' => Date.civil(2025, 3, 30),
24
- '2026' => Date.civil(2026, 3, 20),
25
- '2027' => Date.civil(2027, 3, 9),
26
- '2028' => Date.civil(2028, 2, 26),
27
- '2029' => Date.civil(2029, 2, 15),
28
- '2030' => Date.civil(2030, 2, 4)
29
- }
30
- begin_of_ramadan_feast[year.to_s]
51
+ feast(:ramadan_feast, year, SHAWWAL, 1)
31
52
  end
32
53
 
33
54
  def sacrifice_feast(year)
34
- begin_of_sacrifice_feast = {
35
- '2014' => Date.civil(2014, 10, 4),
36
- '2015' => Date.civil(2015, 9, 24),
37
- '2016' => Date.civil(2016, 9, 12),
38
- '2017' => Date.civil(2017, 9, 1),
39
- '2018' => Date.civil(2018, 8, 21),
40
- '2019' => Date.civil(2019, 8, 11),
41
- '2020' => Date.civil(2020, 7, 31),
42
- '2021' => Date.civil(2021, 7, 20),
43
- '2022' => Date.civil(2022, 7, 9),
44
- '2023' => Date.civil(2023, 6, 28),
45
- '2024' => Date.civil(2024, 6, 16),
46
- '2025' => Date.civil(2025, 6, 6),
47
- '2026' => Date.civil(2026, 5, 27),
48
- '2027' => Date.civil(2027, 5, 16),
49
- '2028' => Date.civil(2028, 5, 5),
50
- '2029' => Date.civil(2029, 4, 24),
51
- '2030' => Date.civil(2030, 4, 13)
52
- }
53
- begin_of_sacrifice_feast[year.to_s]
55
+ feast(:sacrifice_feast, year, DHU_AL_HIJJAH, 10)
56
+ end
57
+
58
+ private
59
+
60
+ def feast(name, year, hijri_month, hijri_day)
61
+ DIYANET_OVERRIDES[[name, year]] ||
62
+ Holidays::Factory::DateCalculator.hijri_date.gregorian_year_occurrence(year, hijri_month, hijri_day)
54
63
  end
55
64
  end
56
65
  end
@@ -72,6 +72,33 @@ module Holidays
72
72
  end
73
73
  end
74
74
 
75
+ # Independence Day observed shift, which varies by region:
76
+ # - us_ri: Rhode Island moves to the following Monday on a weekend
77
+ # (Saturday -> +2, Sunday -> +1).
78
+ # - us_tx: Texas does not shift, the date is returned unchanged.
79
+ # - everyone else: nearest weekday, same as +to_weekday_if_weekend+
80
+ # (Saturday -> Friday, Sunday -> Monday).
81
+ def independence_day(region, date)
82
+ if region == :us_ri
83
+ case date.wday
84
+ when 6
85
+ date + 2
86
+ when 0
87
+ date + 1
88
+ else
89
+ date
90
+ end
91
+ elsif region == :us_tx
92
+ date
93
+ elsif date.wday == 6
94
+ date - 1
95
+ elsif date.wday == 0
96
+ date + 1
97
+ else
98
+ date
99
+ end
100
+ end
101
+
75
102
  def election_day(year)
76
103
  Holidays::Factory::DateCalculator.day_of_month_calculator.call(year, 11, 1, 1) + 1
77
104
  end
@@ -33,6 +33,10 @@ module Holidays
33
33
  @proc_cache[proc_key]
34
34
  end
35
35
 
36
+ def reset!
37
+ @proc_cache = {}
38
+ end
39
+
36
40
  private
37
41
 
38
42
  def validate!(function, function_arguments)
@@ -2,6 +2,7 @@ require 'holidays/date_calculator/easter'
2
2
  require 'holidays/date_calculator/weekend_modifier'
3
3
  require 'holidays/date_calculator/day_of_month'
4
4
  require 'holidays/date_calculator/lunar_date'
5
+ require 'holidays/date_calculator/hijri_date'
5
6
 
6
7
  module Holidays
7
8
  module Factory
@@ -25,10 +26,14 @@ module Holidays
25
26
  end
26
27
 
27
28
  class << self
28
- def lunar_date
29
+ def lunar_date
29
30
  Holidays::DateCalculator::LunarDate.new
30
31
  end
31
32
 
33
+ def hijri_date
34
+ Holidays::DateCalculator::HijriDate.new
35
+ end
36
+
32
37
  def weekend_modifier
33
38
  Holidays::DateCalculator::WeekendModifier.new
34
39
  end
@@ -57,6 +57,8 @@ module Holidays
57
57
  holidays_by_month_repository,
58
58
  regions_repository,
59
59
  custom_methods_repository,
60
+ cache_repository,
61
+ proc_result_cache_repository,
60
62
  )
61
63
  end
62
64
 
@@ -1,3 +1,3 @@
1
1
  module Holidays
2
- VERSION = '11.5.0'
2
+ VERSION = '11.6.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.5.0
4
+ version: 11.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
@@ -197,6 +197,7 @@ files:
197
197
  - lib/holidays/core_extensions/time.rb
198
198
  - lib/holidays/date_calculator/day_of_month.rb
199
199
  - lib/holidays/date_calculator/easter.rb
200
+ - lib/holidays/date_calculator/hijri_date.rb
200
201
  - lib/holidays/date_calculator/lunar_date.rb
201
202
  - lib/holidays/date_calculator/weekend_modifier.rb
202
203
  - lib/holidays/definition/context/function_processor.rb