diff --git a/spec/std/time/location_spec.cr b/spec/std/time/location_spec.cr index 203233c9d737..e0a450160d7e 100644 --- a/spec/std/time/location_spec.cr +++ b/spec/std/time/location_spec.cr @@ -4,31 +4,33 @@ class Time::Location describe Time::Location do describe ".load" do it "loads Europe/Berlin" do - location = Location.load("Europe/Berlin") + with_zoneinfo do + location = Location.load("Europe/Berlin") - location.name.should eq "Europe/Berlin" - standard_time = location.lookup(Time.new(2017, 11, 22)) - standard_time.name.should eq "CET" - standard_time.offset.should eq 3600 - standard_time.dst?.should be_false + location.name.should eq "Europe/Berlin" + standard_time = location.lookup(Time.new(2017, 11, 22)) + standard_time.name.should eq "CET" + standard_time.offset.should eq 3600 + standard_time.dst?.should be_false - summer_time = location.lookup(Time.new(2017, 10, 22)) - summer_time.name.should eq "CEST" - summer_time.offset.should eq 7200 - summer_time.dst?.should be_true + summer_time = location.lookup(Time.new(2017, 10, 22)) + summer_time.name.should eq "CEST" + summer_time.offset.should eq 7200 + summer_time.dst?.should be_true - location.utc?.should be_false - location.fixed?.should be_false + location.utc?.should be_false + location.fixed?.should be_false - with_env("TZ", nil) do - location.local?.should be_false - end + with_env("TZ", nil) do + location.local?.should be_false + end - with_env("TZ", "Europe/Berlin") do - location.local?.should be_true - end + with_env("TZ", "Europe/Berlin") do + location.local?.should be_true + end - Location.load?("Europe/Berlin", Crystal::System::Time.zone_sources).should eq location + Location.load("Europe/Berlin", {ZONEINFO_ZIP}).should eq location + end end it "invalid timezone identifier" do @@ -40,28 +42,34 @@ class Time::Location end it "treats UTC as special case" do - Location.load("UTC").should eq Location::UTC - Location.load("").should eq Location::UTC + with_zoneinfo do + Location.load("UTC").should eq Location::UTC + Location.load("").should eq Location::UTC - # Etc/UTC could be pointing to anything - Location.load("Etc/UTC").should_not eq Location::UTC + # Etc/UTC could be pointing to anything + Location.load("Etc/UTC").should_not eq Location::UTC + end end describe "validating name" do it "absolute path" do - expect_raises(InvalidLocationNameError) do - Location.load("/America/New_York") - end - expect_raises(InvalidLocationNameError) do - Location.load("\\Zulu") + with_zoneinfo do + expect_raises(InvalidLocationNameError) do + Location.load("/America/New_York") + end + expect_raises(InvalidLocationNameError) do + Location.load("\\Zulu") + end end end it "dot dot" do - expect_raises(InvalidLocationNameError) do - Location.load("../zoneinfo/America/New_York") - end - expect_raises(InvalidLocationNameError) do - Location.load("a..") + with_zoneinfo do + expect_raises(InvalidLocationNameError) do + Location.load("../zoneinfo/America/New_York") + end + expect_raises(InvalidLocationNameError) do + Location.load("a..") + end end end end @@ -155,23 +163,40 @@ class Time::Location end it ".local" do - Location.local.should eq Location.load_local + with_zoneinfo do + Location.local.should eq Location.load_local + end Location.local = Location::UTC Location.local.should be Location::UTC end - it ".load_local" do - with_env("TZ", nil) do - Location.load_local.name.should eq "Local" + describe ".load_local" do + it "with unset TZ" do + with_env("TZ", nil) do + Location.load_local.name.should eq "Local" + end end - with_zoneinfo do - with_env("TZ", "Europe/Berlin") do - Location.load_local.name.should eq "Europe/Berlin" + + it "with TZ" do + with_zoneinfo do + with_env("TZ", "Europe/Berlin") do + Location.load_local.name.should eq "Europe/Berlin" + end + end + with_zoneinfo(datapath("zoneinfo")) do + with_env("TZ", "Foo/Bar") do + Location.load_local.name.should eq "Foo/Bar" + end end end - with_env("TZ", "") do - Location.load_local.utc?.should be_true + + it "with empty TZ" do + with_zoneinfo do + with_env("TZ", "") do + Location.load_local.utc?.should be_true + end + end end end diff --git a/spec/std/time/time_spec.cr b/spec/std/time/time_spec.cr index e0ea20c5ed04..eda161b73200 100644 --- a/spec/std/time/time_spec.cr +++ b/spec/std/time/time_spec.cr @@ -391,9 +391,11 @@ describe Time do Time.utc(2014, 1, 2, 3, 4, 5).inspect.should eq "2014-01-02 03:04:05.0 UTC" Time.utc(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789).inspect.should eq "2014-01-02 03:04:05.123456789 UTC" - location = Time::Location.load("Europe/Berlin") - Time.new(2014, 1, 2, 3, 4, 5, location: location).inspect.should eq "2014-01-02 03:04:05.0 +01:00 Europe/Berlin" - Time.new(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789, location: location).inspect.should eq "2014-01-02 03:04:05.123456789 +01:00 Europe/Berlin" + with_zoneinfo do + location = Time::Location.load("Europe/Berlin") + Time.new(2014, 1, 2, 3, 4, 5, location: location).inspect.should eq "2014-01-02 03:04:05.0 +01:00 Europe/Berlin" + Time.new(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789, location: location).inspect.should eq "2014-01-02 03:04:05.123456789 +01:00 Europe/Berlin" + end location = Time::Location.fixed(3601) Time.new(2014, 1, 2, 3, 4, 5, location: location).inspect.should eq "2014-01-02 03:04:05.0 +01:00:01" diff --git a/src/time/location.cr b/src/time/location.cr index cab007e7a9f1..5b70708a65fe 100644 --- a/src/time/location.cr +++ b/src/time/location.cr @@ -334,12 +334,17 @@ class Time::Location def self.load_local : Location case tz = ENV["TZ"]? when "", "UTC" - UTC + return UTC when Nil if localtime = Crystal::System::Time.load_localtime return localtime end else + if zoneinfo = ENV["ZONEINFO"]? + if location = load_from_dir_or_zip(tz, zoneinfo) + return location + end + end if location = load?(tz, Crystal::System::Time.zone_sources) return location end diff --git a/src/time/location/loader.cr b/src/time/location/loader.cr index ed474c094b4c..63cb31db5d88 100644 --- a/src/time/location/loader.cr +++ b/src/time/location/loader.cr @@ -27,22 +27,18 @@ class Time::Location # :nodoc: def self.load_from_dir_or_zip(name : String, source : String) - {% if flag?(:win32) %} - raise NotImplementedError.new("Time::Location.load_from_dir_or_zip") - {% else %} - if source.ends_with?(".zip") - open_file_cached(name, source) do |file| - read_zip_file(name, file) do |io| - read_zoneinfo(name, io) - end - end - else - path = File.expand_path(name, source) - open_file_cached(name, path) do |file| - read_zoneinfo(name, file) + if source.ends_with?(".zip") + open_file_cached(name, source) do |file| + read_zip_file(name, file) do |io| + read_zoneinfo(name, io) end end - {% end %} + else + path = File.join(source, name) + open_file_cached(name, path) do |file| + read_zoneinfo(name, file) + end + end end private def self.open_file_cached(name : String, path : String) @@ -65,18 +61,14 @@ class Time::Location # :nodoc: def self.find_zoneinfo_file(name : String, sources : Enumerable(String)) - {% if flag?(:win32) %} - raise NotImplementedError.new("Time::Location.find_zoneinfo_file") - {% else %} - sources.each do |source| - if source.ends_with?(".zip") - return source if File.exists?(source) - else - path = File.expand_path(name, source) - return source if File.exists?(path) - end + sources.each do |source| + if source.ends_with?(".zip") + return source if File.exists?(source) + else + path = File.join(source, name) + return source if File.exists?(path) end - {% end %} + end end # Parse "zoneinfo" time zone file.