Skip to content

Commit

Permalink
Backport #8880 for v3.9.x: Support both tzinfo v1 and v2 alongwith no…
Browse files Browse the repository at this point in the history
…n-half hour offsets (#9280)

This backports 9c9cf3e to 3.9-stable

Co-authored-by: Phil Ross <philr@users.noreply.github.com>
  • Loading branch information
parkr and philr committed Jan 27, 2023
1 parent fe12951 commit cd39dc9
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 54 deletions.
8 changes: 6 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,12 @@ group :jekyll_optional_dependencies do
gem "yajl-ruby", "~> 1.3.1"
end

# 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 :jruby, :mswin, :mingw, :x64_mingw do
gem "tzinfo", ENV["TZINFO_VERSION"] if ENV["TZINFO_VERSION"]
gem "tzinfo-data"
end
end

#
Expand Down
10 changes: 10 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ install:
environment:
BUNDLE_WITHOUT: "benchmark:development"
matrix:
- RUBY_FOLDER_VER: "26"
TZINFO_VERSION: "~> 1.2"
TEST_SUITE: "test"
- RUBY_FOLDER_VER: "26"
TZINFO_VERSION: "~> 2.0"
TEST_SUITE: "test"
- RUBY_FOLDER_VER: "26"
TEST_SUITE: "test"
- RUBY_FOLDER_VER: "25"
Expand All @@ -26,6 +32,10 @@ environment:
- RUBY_FOLDER_VER: "26"
TEST_SUITE: "profile-docs"
- RUBY_FOLDER_VER: "26"
TZINFO_VERSION: "~> 1.2"
TEST_SUITE: "cucumber"
- RUBY_FOLDER_VER: "26"
TZINFO_VERSION: "~> 2.0"
TEST_SUITE: "cucumber"

test_script:
Expand Down
8 changes: 6 additions & 2 deletions docs/_docs/windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,12 @@ Jekyll now uses a rubygem to internally configure Timezone based on established
While 'new' blogs created with Jekyll v3.4 and greater, will have the following added to their 'Gemfile' by default, existing sites *will* have to update their 'Gemfile' (and installed) 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
```
[IANA-database]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Expand Down
22 changes: 22 additions & 0 deletions features/site_configuration.feature
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,28 @@ Feature: Site configuration
And I should see "Post Layout: <p>content for entry1.</p>\n built at 2013-04-09T09:22:00-10:00" in "_site/2013/04/09/entry1.html"
And I should see "Post Layout: <p>content for entry2.</p>\n built at 2013-04-09T13:14:00-10:00" in "_site/2013/04/09/entry2.html"

Scenario: Generate proper dates with explicitly set timezone (using non-half hour offset )
Given I have a _layouts directory
And I have a page layout that contains "Page Layout: {{ site.posts.size }}"
And I have a post layout that contains "Post Layout: {{ content }} built at {{ page.date | date_to_xmlschema }}"
And I have an "index.html" page with layout "page" that contains "site index page"
And I have a configuration file with:
| key | value |
| timezone | Australia/Eucla |
And I have a _posts directory
And I have the following posts:
| title | date | layout | content |
| entry1 | 2013-04-09 23:22 +0400 | post | content for entry1. |
| entry2 | 2013-04-10 03:14 +0400 | post | content for entry2. |
When I run jekyll build
Then I should get a zero exit status
And the _site directory should exist
And I should see "Page Layout: 2" in "_site/index.html"
And the "_site/2013/04/10/entry1.html" file should exist
And the "_site/2013/04/10/entry2.html" file should exist
And I should see "Post Layout: <p>content for entry1.</p>\n built at 2013-04-10T04:07:00\+08:45" in "_site/2013/04/10/entry1.html"
And I should see "Post Layout: <p>content for entry2.</p>\n built at 2013-04-10T07:59:00\+08:45" in "_site/2013/04/10/entry2.html"

Scenario: Limit the number of posts generated by most recent date
Given I have a _posts directory
And I have a configuration file with:
Expand Down
6 changes: 3 additions & 3 deletions lib/jekyll/commands/new.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ def gemfile_contents
gem "jekyll-feed", "~> 0.6"
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
# and associated library.
install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
gem "tzinfo", "~> 1.2"
platforms :mingw, :x64_mingw, :mswin, :jruby do
gem "tzinfo", ">= 1", "< 3"
gem "tzinfo-data"
end
Expand Down
65 changes: 18 additions & 47 deletions lib/jekyll/utils/win_tz.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 < 0 ? "-" : "+"
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))
# Reference: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
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", absolute_hour(difference).ceil)
mm = modulo.zero? ? "00" : "30"
# Format the hours and minutes as two-digit numbers.
time = format("%<hours>02d:%<minutes>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
Expand Down
31 changes: 31 additions & 0 deletions test/test_win_tz.rb
Original file line number Diff line number Diff line change
@@ -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 |tz, expected|
should "use base offset in winter for #{tz}" do
result = Jekyll::Utils::WinTZ.calculate(tz, Time.utc(2021, 1, 1))
assert_equal expected, result
end
end

[["America/New_York", "WTZ+04:00"], ["Europe/Paris", "WTZ-02:00"]].each do |tz, expected|
should "apply DST in summer for #{tz}" do
result = Jekyll::Utils::WinTZ.calculate(tz, Time.utc(2021, 7, 1))
assert_equal expected, result
end
end

[["Australia/Eucla", "WTZ-08:45"], ["Pacific/Marquesas", "WTZ+09:30"]].each do |tz, expected|
should "handle non zero minutes for #{tz}" do
result = Jekyll::Utils::WinTZ.calculate(tz, 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

0 comments on commit cd39dc9

Please sign in to comment.