holidays 4.4.0 → 4.5.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
  SHA1:
3
- metadata.gz: 0583fff25d319bc53a85cb10ec309c8ad39496fd
4
- data.tar.gz: 9ee50ee21c0b476609d97d7e0b2c68682741389a
3
+ metadata.gz: cb0c1c87e82d392d31c5281d907e58bbe6573683
4
+ data.tar.gz: 7ffb3aa2717b7727898810687778f0df10ec235f
5
5
  SHA512:
6
- metadata.gz: 3ef3930fca96668d9514dbac18bd907b7e198a81592977dabc30d20b095225cd7e1d7cc9a673d27ddf44bb31b5312332325700c9efbbedd2bb084e5456764140
7
- data.tar.gz: 3d7dee33d38a31f68b11fe0ebd138c16beb2c4c0ea469d3eb7b0586993d1b614f0d822c97adfd3763ded3cb6bd2633363b2373f9d68d182b6bc3885fe5eba79a
6
+ metadata.gz: 7f5373bd6b450b42b4a9bb28338c028faecc3a3aea2c52146cd092fbf5ee6b2a144cf00450a5ddd430532737c46c1da590f387e45ddcfb2ca6584903844b4b53
7
+ data.tar.gz: cbaeda3492a457b84d3f2d0d19a8080539fbdf3068aa722e8593a42597897fddf767ba2bbb2668bc2a5a42c254e2f3ae1ad69a36362e9c2f52f925429bda6d90
@@ -1,5 +1,9 @@
1
1
  # Ruby Holidays Gem CHANGELOG
2
2
 
3
+ ## 4.5.0
4
+
5
+ * Add `Holidays.year_holidays` method to obtain all holidays occuring from date to end of year, inclusively (thanks to https://github.com/jonathanpike)
6
+
3
7
  ## 4.4.0
4
8
 
5
9
  * Add Peruvian holiday definitions (https://github.com/Xosmond)
data/README.md CHANGED
@@ -72,6 +72,22 @@ To find and return the next holidays occurring from date, inclusively:
72
72
 
73
73
  Will default to `Date.today` if no date is provided.
74
74
 
75
+ To find all holidays occuring from date to end of year, inclusively:
76
+
77
+ Holidays.year_holidays([:ca_on], Date.civil(2016, 2, 23))
78
+ => [{:name=>"Good Friday",...},
79
+ {name=>"Easter Sunday",...},
80
+ {:name=>"Victoria Day",...},
81
+ {:name=>"Canada Day",...},
82
+ {:name=>"Civic Holiday",...},
83
+ {:name=>"Labour Day",...},
84
+ {:name=>"Thanksgiving",...},
85
+ {:name=>"Remembrance Day",...},
86
+ {:name=>"Christmas Day",...},
87
+ {:name=>"Boxing Day",...}]
88
+
89
+ Will default to `Date.today` if no date is provided.
90
+
75
91
  ### Loading Custom Definitions on the fly
76
92
 
77
93
  Load custom definitions file on the fly and use them immediately.
@@ -160,6 +160,50 @@ module Holidays
160
160
  UseCaseFactory.next_holiday.call(holidays_count, from_date, date_driver_hash, regions, observed, informal)
161
161
  end
162
162
 
163
+ # Get all holidays occuring from date to end of year, inclusively.
164
+ #
165
+ # Returns an array of hashes or nil.
166
+ #
167
+ # Incoming arguments are below:
168
+ # [<tt>options</tt>] One or more region symbols, <tt>:informal</tt> and/or <tt>:observed</tt>.
169
+ # [<tt>from_date</tt>] Ruby Date object. This is an optional param, defaulted today.
170
+ #
171
+ # ==== Example
172
+ # Date.today
173
+ # => Tue, 23 Feb 2016
174
+ #
175
+ # regions = [:ca_on]
176
+ #
177
+ # Holidays.year_holidays(regions)
178
+ # => [{:name=>"Good Friday",...},
179
+ # {name=>"Easter Sunday",...},
180
+ # {:name=>"Victoria Day",...},
181
+ # {:name=>"Canada Day",...},
182
+ # {:name=>"Civic Holiday",...},
183
+ # {:name=>"Labour Day",...},
184
+ # {:name=>"Thanksgiving",...},
185
+ # {:name=>"Remembrance Day",...},
186
+ # {:name=>"Christmas Day",...},
187
+ # {:name=>"Boxing Day",...}]
188
+ def year_holidays(options, from_date = Date.today)
189
+ raise ArgumentError if options.empty?
190
+ raise ArgumentError unless options.is_a?(Array)
191
+
192
+ # remove the timezone
193
+ from_date = from_date.new_offset(0) + from_date.offset if from_date.respond_to?(:new_offset)
194
+
195
+ from_date = get_date(from_date)
196
+ to_date = Date.new(from_date.year, 12, 31)
197
+ regions, observed, informal = OptionFactory.parse_options.call(options)
198
+
199
+ # This could be smarter but I don't have any evidence that just checking for
200
+ # the next 12 months will cause us issues. If it does we can implement something
201
+ # smarter here to check in smaller increments.
202
+ date_driver_hash = UseCaseFactory.dates_driver_builder.call(from_date, from_date >> 12)
203
+
204
+ UseCaseFactory.year_holiday.call(from_date, to_date, date_driver_hash, regions, observed, informal)
205
+ end
206
+
163
207
  # Allows a developer to explicitly calculate and cache holidays within a given period
164
208
  def cache_between(start_date, end_date, *options)
165
209
  start_date, end_date = get_date(start_date), get_date(end_date)
@@ -29,6 +29,24 @@ module Holidays
29
29
  holidays && !holidays.empty?
30
30
  end
31
31
 
32
+ # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
33
+ # The +options+ parameter is a hash with a combination of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>.
34
+ #
35
+ # Date.new(2007, 5, 12).change(day: 1) # => Date.new(2007, 5, 1)
36
+ # Date.new(2007, 5, 12).change(year: 2005, month: 1) # => Date.new(2005, 1, 12)
37
+ def change(options)
38
+ ::Date.new(
39
+ options.fetch(:year, year),
40
+ options.fetch(:month, month),
41
+ options.fetch(:day, day)
42
+ )
43
+ end
44
+
45
+ def end_of_month
46
+ last_day = ::Time.days_in_month( self.month, self.year )
47
+ change(:day => last_day)
48
+ end
49
+
32
50
  module ClassMethods
33
51
  def calculate_mday(year, month, week, wday)
34
52
  Holidays::DateCalculatorFactory.day_of_month_calculator.call(year, month, week, wday)
@@ -0,0 +1,23 @@
1
+ module Holidays
2
+ module CoreExtensions
3
+ module Time
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
10
+
11
+ # Returns the number of days in the given month.
12
+ # If no year is specified, it will use the current year.
13
+ def days_in_month(month, year = current.year)
14
+ if month == 2 && ::Date.gregorian_leap?(year)
15
+ 29
16
+ else
17
+ COMMON_YEAR_DAYS_IN_MONTH[month]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ module Holidays
2
+ module UseCase
3
+ module Context
4
+ class YearHoliday
5
+ include ContextCommon
6
+
7
+ def initialize(holidays_by_month_repo, day_of_month_calculator, custom_methods_repo, proc_result_cache_repo)
8
+ @holidays_by_month_repo = holidays_by_month_repo
9
+ @day_of_month_calculator = day_of_month_calculator
10
+ @custom_methods_repo = custom_methods_repo
11
+ @proc_result_cache_repo = proc_result_cache_repo
12
+ end
13
+
14
+ def call(from_date, to_date, dates_driver, regions, observed, informal)
15
+ validate!(from_date, to_date, dates_driver, regions)
16
+ holidays = []
17
+ ret_holidays = []
18
+
19
+ ret_holidays = make_date_array(dates_driver, regions, observed, informal)
20
+ ret_holidays.each do |holiday|
21
+ if holiday[:date] >= from_date && holiday[:date] <= to_date
22
+ holidays << holiday
23
+ end
24
+ end
25
+
26
+ holidays.sort{|a, b| a[:date] <=> b[:date] }
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :holidays_by_month_repo,
32
+ :day_of_month_calculator,
33
+ :custom_methods_repo,
34
+ :proc_result_cache_repo
35
+
36
+ def validate!(from_date, to_date, dates_driver, regions)
37
+ raise ArgumentError unless from_date
38
+ raise ArgumentError unless to_date
39
+
40
+ raise ArgumentError if dates_driver.nil? || dates_driver.empty?
41
+
42
+ dates_driver.each do |year, months|
43
+ raise ArgumentError if months.nil? || months.empty?
44
+ end
45
+
46
+ raise ArgumentError if regions.nil? || regions.empty?
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -2,6 +2,7 @@ require 'holidays/use_case/context/context_common'
2
2
  require 'holidays/use_case/context/between'
3
3
  require 'holidays/use_case/context/next_holiday'
4
4
  require 'holidays/use_case/context/dates_driver_builder'
5
+ require 'holidays/use_case/context/year_holiday'
5
6
 
6
7
  module Holidays
7
8
  class UseCaseFactory
@@ -23,6 +24,15 @@ module Holidays
23
24
  )
24
25
  end
25
26
 
27
+ def year_holiday
28
+ UseCase::Context::YearHoliday.new(
29
+ DefinitionFactory.holidays_by_month_repository,
30
+ DateCalculatorFactory.day_of_month_calculator,
31
+ DefinitionFactory.custom_methods_repository,
32
+ DefinitionFactory.proc_result_cache_repository,
33
+ )
34
+ end
35
+
26
36
  def dates_driver_builder
27
37
  UseCase::Context::DatesDriverBuilder.new
28
38
  end
@@ -1,3 +1,3 @@
1
1
  module Holidays
2
- VERSION = '4.4.0'
2
+ VERSION = '4.5.0'
3
3
  end
@@ -0,0 +1,60 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../../test_helper'
2
+
3
+ require 'holidays/core_extensions/date'
4
+ require 'holidays/core_extensions/time'
5
+
6
+ class Date
7
+ include Holidays::CoreExtensions::Date
8
+ end
9
+
10
+ class Time
11
+ include Holidays::CoreExtensions::Time
12
+ end
13
+
14
+ class CoreExtensionDateTimeTests < Test::Unit::TestCase
15
+ def setup
16
+ @date = Date.civil(2008,1,1)
17
+ end
18
+
19
+ def test_change_method
20
+ actual = @date.change(day: 5)
21
+ assert_equal Date.civil(2008,1,5), actual
22
+
23
+ actual = @date.change(year: 2016)
24
+ assert_equal Date.civil(2016,1,1), actual
25
+
26
+ actual = @date.change(month: 5)
27
+ assert_equal Date.civil(2008,5,1), actual
28
+
29
+ actual = @date.change(year: 2015, month: 5, day: 3)
30
+ assert_equal Date.civil(2015,5,3), actual
31
+ end
32
+
33
+ def test_end_of_month_method
34
+ # Works for month with 31 days
35
+ actual = @date.end_of_month
36
+ assert_equal Date.civil(2008,1,31), actual
37
+
38
+ # Works for month with 30 days
39
+ actual = Date.civil(2008,9,5).end_of_month
40
+ assert_equal Date.civil(2008,9,30), actual
41
+
42
+ # Works for leap year
43
+ actual = Date.civil(2016,2,1).end_of_month
44
+ assert_equal = Date.civil(2016,2,29), actual
45
+ end
46
+
47
+ def test_days_in_month_method
48
+ # Works for month with 31 days
49
+ actual = Time.days_in_month(1, 2008)
50
+ assert_equal 31, actual
51
+
52
+ # Works for month with 30 days
53
+ actual = Time.days_in_month(9, 2008)
54
+ assert_equal 30, actual
55
+
56
+ # Works for leap year
57
+ actual = Time.days_in_month(2, 2016)
58
+ assert_equal 29, actual
59
+ end
60
+ end
@@ -11,12 +11,17 @@ require 'mocha/test_unit'
11
11
  require 'date'
12
12
  require 'holidays'
13
13
  require 'holidays/core_extensions/date'
14
+ require 'holidays/core_extensions/time'
14
15
 
15
16
  # Loads core extension for use in various definition tests as necessary
16
17
  class Date
17
18
  include Holidays::CoreExtensions::Date
18
19
  end
19
20
 
21
+ class Time
22
+ include Holidays::CoreExtensions::Time
23
+ end
24
+
20
25
  module Holidays
21
26
  # Test region used for generating a holiday on Date.today
22
27
  module Test # :nodoc:
@@ -139,6 +139,61 @@ class HolidaysTests < Test::Unit::TestCase
139
139
  end
140
140
  end
141
141
 
142
+ def test_year_holidays
143
+ # Should return 10 holidays from February 23 to December 31
144
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(2016, 2, 23))
145
+ assert_equal 10, holidays.length
146
+
147
+ # Must have options (Regions)
148
+ assert_raises ArgumentError do
149
+ Holidays.year_holidays([], Date.civil(2016, 2, 23))
150
+ end
151
+
152
+ # Options must be in the form of an array.
153
+ assert_raises ArgumentError do
154
+ Holidays.year_holidays(:ca_on, Date.civil(2016, 2, 23))
155
+ end
156
+ end
157
+
158
+ def test_year_holidays_with_specified_year
159
+ # Should return all 12 holidays for 2016 in Ontario, Canada
160
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(2016, 1, 1))
161
+ assert_equal 12, holidays.length
162
+
163
+ # Should return all 12 holidays for 2016 in Australia
164
+ holidays = Holidays.year_holidays([:au], Date.civil(2016, 1, 1))
165
+ assert_equal 5, holidays.length
166
+ end
167
+
168
+ def test_year_holidays_without_specified_year
169
+ # Gets holidays for current year from today's date
170
+ holidays = Holidays.year_holidays([:ca_on])
171
+ assert_equal holidays.first[:date].year, Date.today.year
172
+ end
173
+
174
+ def test_year_holidays_feb_29_on_non_leap_year
175
+ # Should throw argument error for invalid date
176
+ assert_raises ArgumentError do
177
+ Holidays.year_holidays([:ca_on], Date.civil(2015, 2, 29))
178
+ end
179
+ end
180
+
181
+ def test_year_holidays_random_years
182
+ # Should be 1 less holiday, as Family day didn't exist in Ontario in 1990
183
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(1990, 1, 1))
184
+ assert_equal 11, holidays.length
185
+
186
+ # Family day still didn't exist in 2000
187
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(2000, 1, 1))
188
+ assert_equal 11, holidays.length
189
+
190
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(2020, 1, 1))
191
+ assert_equal 12, holidays.length
192
+
193
+ holidays = Holidays.year_holidays([:ca_on], Date.civil(2050, 1, 1))
194
+ assert_equal 12, holidays.length
195
+ end
196
+
142
197
  def test_sub_regions
143
198
  # Should return Victoria Day.
144
199
  holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :ca)
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: 4.4.0
4
+ version: 4.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dunae
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-06-18 00:00:00.000000000 Z
12
+ date: 2016-06-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -230,6 +230,7 @@ files:
230
230
  - lib/generated_definitions/za.rb
231
231
  - lib/holidays.rb
232
232
  - lib/holidays/core_extensions/date.rb
233
+ - lib/holidays/core_extensions/time.rb
233
234
  - lib/holidays/date_calculator/day_of_month.rb
234
235
  - lib/holidays/date_calculator/easter.rb
235
236
  - lib/holidays/date_calculator/weekend_modifier.rb
@@ -256,6 +257,7 @@ files:
256
257
  - lib/holidays/use_case/context/context_common.rb
257
258
  - lib/holidays/use_case/context/dates_driver_builder.rb
258
259
  - lib/holidays/use_case/context/next_holiday.rb
260
+ - lib/holidays/use_case/context/year_holiday.rb
259
261
  - lib/holidays/use_case_factory.rb
260
262
  - lib/holidays/version.rb
261
263
  - test/data/test_custom_govt_holiday_defs.yaml
@@ -320,6 +322,7 @@ files:
320
322
  - test/defs/test_defs_vi.rb
321
323
  - test/defs/test_defs_za.rb
322
324
  - test/holidays/core_extensions/test_date.rb
325
+ - test/holidays/core_extensions/test_date_time.rb
323
326
  - test/holidays/date_calculator/test_day_of_month.rb
324
327
  - test/holidays/date_calculator/test_easter_gregorian.rb
325
328
  - test/holidays/date_calculator/test_easter_julian.rb
@@ -437,6 +440,7 @@ test_files:
437
440
  - test/defs/test_defs_vi.rb
438
441
  - test/defs/test_defs_za.rb
439
442
  - test/holidays/core_extensions/test_date.rb
443
+ - test/holidays/core_extensions/test_date_time.rb
440
444
  - test/holidays/date_calculator/test_day_of_month.rb
441
445
  - test/holidays/date_calculator/test_easter_gregorian.rb
442
446
  - test/holidays/date_calculator/test_easter_julian.rb