Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport #8880 for v3.9.x: Support both tzinfo v1 and v2 alongwith non-half hour offsets #9280

Merged
merged 6 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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