From 84f34325b8d4868fe20a71972c3f45f25c244414 Mon Sep 17 00:00:00 2001 From: Paul Gideon Dann Date: Mon, 18 Aug 2014 11:09:26 +0100 Subject: [PATCH 1/3] Ensure that the cut-off time is in the same timezone as the extended object If we don't match the UTC offset, and the system timezone is not UTC, you end up with the following scenario: = Scenario 1 (correct) Time.now # 2014-08-15 15:30:00 +0100 Time.now.cut_off_time # 2014-08-15 16:00:00 +0100 Time.now.despatch_day # Fri, 15 Aug 2014 = Scenario 2 (incorrect) Time.zone.now # Fri, 15 Aug 2014 15:30:00 BST +01:00 Time.zone.now.cut_off_time # Fri, 15 Aug 2014 16:00:00 BST +01:00 Time.zone.now.despatch_day # Mon, 18 Aug 2014 The incorrect result in Scenario 2 is due to the fact that the ActiveSupport::TimeWithZone class wraps a UTC time object and maintains the timezone data separately. When DateExtension.despatch_day is called in Scenario 2, the context is: self # 2014-08-15 15:30:00 UTC cut_off_time # 2014-08-15 16:00:00 +0100 This comparison is incorrect due to the mismatch in timezones and produces the wrong result. The fix is to construct the cut_off_time based on the timezone of #self. --- lib/nextday/date_extension.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nextday/date_extension.rb b/lib/nextday/date_extension.rb index f5b6ef6..bd5f0e1 100644 --- a/lib/nextday/date_extension.rb +++ b/lib/nextday/date_extension.rb @@ -30,7 +30,8 @@ def delivery_day def cut_off_time hour, minute = Config.cut_off_hour, Config.cut_off_minute - Time.new(year, month, day, hour, minute) + utc_offset = self.utc_offset unless not self.respond_to?(:utc_offset) + Time.new(year, month, day, hour, minute, 0, utc_offset) end ## From c521aadf298b72258c28063613125d86268169b0 Mon Sep 17 00:00:00 2001 From: Rich Grundy Date: Tue, 30 Dec 2014 11:26:06 +0000 Subject: [PATCH 2/3] Removing hard coded public holidays. Switched to fetching the public holidays from the Government API. This ensures that the dates are always up to date and correct (with a server reboot anyhow). --- lib/nextday.rb | 4 ++ lib/nextday/exceptions.rb | 3 ++ lib/nextday/holidays.rb | 12 ++--- lib/nextday/public_holidays.rb | 89 +++++++++++----------------------- 4 files changed, 41 insertions(+), 67 deletions(-) create mode 100644 lib/nextday/exceptions.rb diff --git a/lib/nextday.rb b/lib/nextday.rb index 2c58bf3..6de46d4 100644 --- a/lib/nextday.rb +++ b/lib/nextday.rb @@ -1,7 +1,11 @@ require 'date' require 'time' +require 'json' +require 'uri' +require 'open-uri' require "nextday/version" +require "nextday/exceptions" require "nextday/config" require "nextday/holiday" diff --git a/lib/nextday/exceptions.rb b/lib/nextday/exceptions.rb new file mode 100644 index 0000000..148671e --- /dev/null +++ b/lib/nextday/exceptions.rb @@ -0,0 +1,3 @@ +module Nextday + class Error < StandardError; end +end diff --git a/lib/nextday/holidays.rb b/lib/nextday/holidays.rb index 07340c6..a278462 100644 --- a/lib/nextday/holidays.rb +++ b/lib/nextday/holidays.rb @@ -1,19 +1,19 @@ require 'singleton' module Nextday - + class Holidays include Enumerable include Singleton - + def initialize - @holidays = PUBLIC_HOLIDAYS + @holidays = PublicHolidays.new.fetch end - + def each(&block) @holidays.each{|holiday| block.call(holiday)} end - + ## # Returning all the dates holidays occur # @@ -21,7 +21,7 @@ def each(&block) def self.dates instance.map(&:date) end - + ## # Find the first holiday for the supplied date # @param [Date] format the format type, `:text` or `:html` diff --git a/lib/nextday/public_holidays.rb b/lib/nextday/public_holidays.rb index 624e9eb..a851780 100644 --- a/lib/nextday/public_holidays.rb +++ b/lib/nextday/public_holidays.rb @@ -1,62 +1,29 @@ module Nextday - ## - # Bank and public holidays in England and Wales - # Includes substitute days if holiday lands on a weekend - # http://www.direct.gov.uk/en/Employment/Employees/Timeoffandholidays/DG_073741 - # - # Be careful when adding new holidays, please specify the date as '1' not '01' - # - BANK_AND_PUBLIC_HOLIDAYS_ENGLAND_AND_WALES = [ - Holiday.new("Spring Bank Holiday", Date.new(2011, 5, 30)), - Holiday.new("Spring Bank Holiday", Date.new(2012, 6, 4)), - Holiday.new("Spring Bank Holiday", Date.new(2013, 5, 27)), - Holiday.new("Spring Bank Holiday", Date.new(2014, 5, 26)), - Holiday.new("Spring Bank Holiday", Date.new(2015, 5, 25)), - - Holiday.new("Early May Bank Holiday", Date.new(2011, 5, 2)), - Holiday.new("Early May Bank Holiday", Date.new(2012, 5, 7)), - Holiday.new("Early May Bank Holiday", Date.new(2013, 5, 6)), - Holiday.new("Early May Bank Holiday", Date.new(2014, 5, 5)), - Holiday.new("Early May Bank Holiday", Date.new(2015, 5, 4)), - - Holiday.new("Queen's Diamond Jubilee", Date.new(2012, 6, 5)), - - Holiday.new("Good Friday", Date.new(2011, 4, 22)), - Holiday.new("Good Friday", Date.new(2012, 4, 06)), - Holiday.new("Good Friday", Date.new(2013, 3, 29)), - Holiday.new("Good Friday", Date.new(2014, 4, 18)), - Holiday.new("Good Friday", Date.new(2015, 4, 3)), - - Holiday.new("Summer Bank Holiday", Date.new(2011, 8, 29)), - Holiday.new("Summer Bank Holiday", Date.new(2012, 8, 27)), - Holiday.new("Summer Bank Holiday", Date.new(2013, 8, 26)), - Holiday.new("Summer Bank Holiday", Date.new(2014, 8, 25)), - Holiday.new("Summer Bank Holiday", Date.new(2015, 8, 31)), - - Holiday.new("New Year's Day", Date.new(2011, 1, 3)), - Holiday.new("New Year's Day", Date.new(2012, 1, 2)), - Holiday.new("New Year's Day", Date.new(2013, 1, 1)), - Holiday.new("New Year's Day", Date.new(2014, 1, 1)), - Holiday.new("New Year's Day", Date.new(2015, 1, 1)), - - Holiday.new("Christmas Day", Date.new(2011, 12, 26)), - Holiday.new("Christmas Day", Date.new(2012, 12, 25)), - Holiday.new("Christmas Day", Date.new(2013, 12, 25)), - Holiday.new("Christmas Day", Date.new(2014, 12, 25)), - Holiday.new("Christmas Day", Date.new(2015, 12, 25)), - - Holiday.new("Easter Monday", Date.new(2011, 4, 25)), - Holiday.new("Easter Monday", Date.new(2012, 4, 9)), - Holiday.new("Easter Monday", Date.new(2013, 4, 1)), - Holiday.new("Easter Monday", Date.new(2014, 4, 21)), - Holiday.new("Easter Monday", Date.new(2015, 4, 6)), - - Holiday.new("Boxing Day", Date.new(2011, 12, 27)), - Holiday.new("Boxing Day", Date.new(2012, 12, 26)), - Holiday.new("Boxing Day", Date.new(2013, 12, 26)), - Holiday.new("Boxing Day", Date.new(2014, 12, 26)), - Holiday.new("Boxing Day", Date.new(2015, 12, 28)) - ] - - PUBLIC_HOLIDAYS = BANK_AND_PUBLIC_HOLIDAYS_ENGLAND_AND_WALES -end \ No newline at end of file + class PublicHolidays + attr_reader :raw_data + + BASE_URL = 'https://www.gov.uk/bank-holidays.json' + DEFAULT_DIVISION = 'england-and-wales' + + def initialize + @raw_data = ::JSON.parse(::URI.parse(BASE_URL).read) + rescue OpenURI::HTTPError, JSON::ParserError + raise Nextday::Error, 'Unable to load any public holidays.' + end + + def fetch + @data ||= parse(DEFAULT_DIVISION) + end + + private + def parse(division) + div = @raw_data[division] + raise Error, "Unable to find division #{division}" unless div + raise Error, "Unable to find events for division #{division}" unless div['events'] + + div['events'].map { |e| + Holiday.new(e['title'], Date.parse(e['date'])) + } + end + end +end From 1ca8901fd5332dad493621369c3d9afdf0b2f6fb Mon Sep 17 00:00:00 2001 From: Rich Grundy Date: Tue, 30 Dec 2014 11:25:04 +0000 Subject: [PATCH 3/3] Bumping version. --- lib/nextday/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nextday/version.rb b/lib/nextday/version.rb index a74682e..f00bed3 100644 --- a/lib/nextday/version.rb +++ b/lib/nextday/version.rb @@ -1,3 +1,3 @@ module Nextday - VERSION = "0.4.0" + VERSION = "0.5.0" end