diff --git a/Gemfile b/Gemfile index 92797b42..378f6b82 100644 --- a/Gemfile +++ b/Gemfile @@ -79,6 +79,9 @@ group :jekyll_optional_dependencies do gem "classifier-reborn", "~> 2.0" gem "liquid-c", "~> 3.0" end + + # Windows does not include zoneinfo files, so bundle the tzinfo-data gem + gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] end # diff --git a/docs/_docs/windows.md b/docs/_docs/windows.md index 05f3bbff..ab536382 100644 --- a/docs/_docs/windows.md +++ b/docs/_docs/windows.md @@ -34,6 +34,19 @@ the site generation process. It can be done with the following command: $ chcp 65001 ``` +## Timezone Management + +Since Windows doesn't have a native source of zoneinfo data, the Ruby Interpreter would not understand IANA Timezones and hence using them had the `TZ` environment variable default to UTC/GMT 00:00. +Though Windows users could alternatively define their blog's timezone by setting the key to use POSIX format of defining timezones, it wasn't as user-friendly when it came to having the clock altered to changing DST-rules. + +Jekyll now uses a rubygem to internally configure Timezone based on established [IANA Timezone Database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). +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] +``` + ## Auto-regeneration As of v1.3.0, Jekyll uses the `listen` gem to watch for changes when the diff --git a/features/site_configuration.feature b/features/site_configuration.feature index 016ce28f..2d00f9b7 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -161,8 +161,8 @@ Feature: Site configuration 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 | UTC+04:00 | + | key | value | + | timezone | America/New_York | And I have a _posts directory And I have the following posts: | title | date | layout | content | @@ -172,8 +172,10 @@ Feature: Site configuration 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 I should see "Post Layout:
content for entry1.
\n built at 2013-04-09T23:22:00-04:00" in "_site/2013/04/09/entry1.html" - And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T03:14:00-04:00" in "_site/2013/04/10/entry2.html" + And I should see "Post Layout:content for entry1.
\n built at 2013-04-09T23:22:00-04:00" in "_site/2013/04/09/entry1.html" unless Windows + And I should see "Post Layout:content for entry1.
\n built at 2013-04-09T22:22:00-05:00" in "_site/2013/04/09/entry1.html" if on Windows + And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T03:14:00-04:00" in "_site/2013/04/10/entry2.html" unless Windows + And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T02:14:00-05:00" in "_site/2013/04/10/entry2.html" if on Windows Scenario: Generate proper dates with explicitly set timezone (different than posts' time) Given I have a _layouts directory @@ -181,8 +183,8 @@ Feature: Site configuration 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 | UTC+10:00 | + | key | value | + | timezone | Pacific/Honolulu | And I have a _posts directory And I have the following posts: | title | date | layout | content | diff --git a/lib/jekyll.rb b/lib/jekyll.rb index 6cfbd70f..25bbaa0a 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -119,7 +119,11 @@ module Jekyll # Returns nothing # rubocop:disable Style/AccessorMethodName def set_timezone(timezone) - ENV["TZ"] = timezone + ENV["TZ"] = if Utils::Platforms.really_windows? + Utils::WinTZ.calculate(timezone) + else + timezone + end end # rubocop:enable Style/AccessorMethodName diff --git a/lib/jekyll/commands/new.rb b/lib/jekyll/commands/new.rb index 8319bd7e..561ae861 100644 --- a/lib/jekyll/commands/new.rb +++ b/lib/jekyll/commands/new.rb @@ -84,6 +84,10 @@ gem "minima", "~> 2.0" group :jekyll_plugins do gem "jekyll-feed", "~> 0.6" end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] + RUBY end diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb index f870ea85..23bacdab 100644 --- a/lib/jekyll/utils.rb +++ b/lib/jekyll/utils.rb @@ -4,6 +4,7 @@ module Jekyll extend self autoload :Platforms, "jekyll/utils/platforms" autoload :Ansi, "jekyll/utils/ansi" + autoload :WinTZ, "jekyll/utils/win_tz" # Constants for use in #slugify SLUGIFY_MODES = %w(raw default pretty ascii).freeze diff --git a/lib/jekyll/utils/win_tz.rb b/lib/jekyll/utils/win_tz.rb new file mode 100644 index 00000000..0c2b5bd2 --- /dev/null +++ b/lib/jekyll/utils/win_tz.rb @@ -0,0 +1,73 @@ +module Jekyll + module Utils + module WinTZ + extend self + + # Public: Calculate the Timezone for Windows when the config file has a defined + # 'timezone' key. + # + # timezone - the IANA Time Zone specified in "_config.yml" + # + # Returns a string that ultimately re-defines ENV["TZ"] in Windows + def calculate(timezone) + External.require_with_graceful_fail("tzinfo") + tz = TZInfo::Timezone.get(timezone) + difference = Time.now.to_i - tz.now.to_i + # + # 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)) + # + # 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" + + Jekyll.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}" + # + # 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 + end + end + end +end