From 77813426fb56c19cd3870981a43da3904e3ba934 Mon Sep 17 00:00:00 2001 From: Phil Ross Date: Sun, 14 Nov 2021 22:10:51 +0000 Subject: [PATCH] Support both tzinfo v1 and v2. Support non-half hour offsets. Use the defined offset (in a v1 and v2 compatible way) instead of determining the offset from the difference between local time and UTC. Change the minutes calculation to allow for time zones that don't use hour or half hour offsets (e.g. Australia/Eucla's UTC+08:45). Resolves #8516. --- Gemfile | 9 +---- docs/_docs/installation/windows.md | 20 +++------- lib/jekyll/commands/new.rb | 2 +- lib/jekyll/utils/win_tz.rb | 63 ++++++++---------------------- test/test_win_tz.rb | 31 +++++++++++++++ 5 files changed, 57 insertions(+), 68 deletions(-) create mode 100644 test/test_win_tz.rb diff --git a/Gemfile b/Gemfile index be1aca20f9a..d8a150527c4 100644 --- a/Gemfile +++ b/Gemfile @@ -32,6 +32,8 @@ group :test do gem "test-theme", :path => File.expand_path("test/fixtures/test-theme", __dir__) gem "test-theme-skinny", :path => File.expand_path("test/fixtures/test-theme-skinny", __dir__) gem "test-theme-symlink", :path => File.expand_path("test/fixtures/test-theme-symlink", __dir__) + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" if RUBY_ENGINE == "jruby" gem "http_parser.rb", "~> 0.6.0" @@ -81,13 +83,6 @@ group :jekyll_optional_dependencies do gem "liquid-c", "~> 4.0" gem "yajl-ruby", "~> 1.4" end - - # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem - # and associated library - platforms :jruby, :mswin, :mingw, :x64_mingw do - gem "tzinfo", "~> 1.2" - gem "tzinfo-data" - end end # diff --git a/docs/_docs/installation/windows.md b/docs/_docs/installation/windows.md index eacd92c6942..c7d77ed0fbb 100644 --- a/docs/_docs/installation/windows.md +++ b/docs/_docs/installation/windows.md @@ -121,22 +121,14 @@ While 'new' blogs created with Jekyll v3.4 and greater, will have the following sites *will* have to update their `Gemfile` (and installed gems) to enable development on Windows: ```ruby -# Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" +end ``` -
-
TZInfo 2.0 incompatibility
-

- Version 2.0 of the TZInfo library has introduced a change in how timezone offsets are calculated. - This will result in incorrect date and time for your posts when the site is built with Jekyll 3.x on Windows. -

-

- We therefore recommend that you lock the Timezone library to version 1.2 and above by listing - gem 'tzinfo', '~> 1.2' in your Gemfile. -

-
- ## Auto Regeneration Jekyll uses the `listen` gem to watch for changes when the `--watch` switch is specified during a build or serve. diff --git a/lib/jekyll/commands/new.rb b/lib/jekyll/commands/new.rb index 150b4aa7360..f85026baf56 100644 --- a/lib/jekyll/commands/new.rb +++ b/lib/jekyll/commands/new.rb @@ -92,7 +92,7 @@ def gemfile_contents # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem # and associated library. platforms :mingw, :x64_mingw, :mswin, :jruby do - gem "tzinfo", "~> 1.2" + gem "tzinfo", ">= 1", "< 3" gem "tzinfo-data" end diff --git a/lib/jekyll/utils/win_tz.rb b/lib/jekyll/utils/win_tz.rb index 9c55c42eac4..9d25a1fd753 100644 --- a/lib/jekyll/utils/win_tz.rb +++ b/lib/jekyll/utils/win_tz.rb @@ -11,64 +11,35 @@ module WinTZ # timezone - the IANA Time Zone specified in "_config.yml" # # Returns a string that ultimately re-defines ENV["TZ"] in Windows - def calculate(timezone) + def calculate(timezone, now = Time.now) External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo) tz = TZInfo::Timezone.get(timezone) - difference = Time.now.to_i - tz.now.to_i + + # + # Use period_for_utc and utc_total_offset instead of + # period_for and observed_utc_offset for compatibility with tzinfo v1. + offset = tz.period_for_utc(now.getutc).utc_total_offset + # # POSIX style definition reverses the offset sign. # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian # is denoted as: # EST+5 (or) EST+05:00 # Reference: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html - sign = difference.negative? ? "-" : "+" - offset = sign == "-" ? "+" : "-" unless difference.zero? - # - # convert the difference (in seconds) to hours, as a rational number, and perform - # a modulo operation on it. - modulo = modulo_of(rational_hour(difference)) + sign = offset.positive? ? "-" : "+" + + rational_hours = offset.abs.to_r / 3600 + hours = rational_hours.to_i + minutes = ((rational_hours - hours) * 60).to_i + # - # Format the hour as a two-digit number. - # Establish the minutes based on modulo expression. - hh = format("%02d", :hour => absolute_hour(difference).ceil) - mm = modulo.zero? ? "00" : "30" + # Format the hours and minutes as two-digit numbers. + time = format("%02d:%02d", hours: hours, minutes: minutes) - Jekyll.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}" + Jekyll.logger.debug "Timezone:", "#{timezone} #{sign}#{time}" # # Note: The 3-letter-word below doesn't have a particular significance. - "WTZ#{sign}#{hh}:#{mm}" - end - - private - - # Private: Convert given seconds to an hour as a rational number. - # - # seconds - supplied as an integer, it is converted to a rational number. - # 3600 - no. of seconds in an hour. - # - # Returns a rational number. - def rational_hour(seconds) - seconds.to_r / 3600 - end - - # Private: Convert given seconds to an hour as an absolute number. - # - # seconds - supplied as an integer, it is converted to its absolute. - # 3600 - no. of seconds in an hour. - # - # Returns an integer. - def absolute_hour(seconds) - seconds.abs / 3600 - end - - # Private: Perform a modulo operation on a given fraction. - # - # fraction - supplied as a rational number, its numerator is divided - # by its denominator and the remainder returned. - # - # Returns an integer. - def modulo_of(fraction) - fraction.numerator % fraction.denominator + "WTZ#{sign}#{time}" end end end diff --git a/test/test_win_tz.rb b/test/test_win_tz.rb new file mode 100644 index 00000000000..e1d60908c79 --- /dev/null +++ b/test/test_win_tz.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "helper" + +class TestWinTz < JekyllUnitTest + [["America/New_York", "WTZ+05:00"], ["Europe/Paris", "WTZ-01:00"]].each do |timezone, expected| + should "use base offset in winter for #{timezone}" do + result = Jekyll::Utils::WinTZ.calculate(timezone, Time.utc(2021, 1, 1)) + assert_equal expected, result + end + end + + [["America/New_York", "WTZ+04:00"], ["Europe/Paris", "WTZ-02:00"]].each do |timezone, expected| + should "apply DST in summer for #{timezone}" do + result = Jekyll::Utils::WinTZ.calculate(timezone, Time.utc(2021, 7, 1)) + assert_equal expected, result + end + end + + [["Australia/Eucla", "WTZ-08:45"], ["Pacific/Marquesas", "WTZ+09:30"]].each do |timezone, expected| + should "handle non zero minutes for #{timezone}" do + result = Jekyll::Utils::WinTZ.calculate(timezone, Time.utc(2021, 1, 1)) + assert_equal expected, result + end + end + + should "return zero for UTC" do + result = Jekyll::Utils::WinTZ.calculate("UTC") + assert_equal "WTZ+00:00", result + end +end \ No newline at end of file