diff --git a/spec/std/time/location_spec.cr b/spec/std/time/location_spec.cr index c618f20a1024..92fca1322647 100644 --- a/spec/std/time/location_spec.cr +++ b/spec/std/time/location_spec.cr @@ -30,7 +30,6 @@ class Time::Location summer_time.offset.should eq 7200 summer_time.dst?.should be_true - location.unspecified?.should be_false location.utc?.should be_false location.fixed?.should be_false @@ -81,12 +80,14 @@ class Time::Location end context "with ZONEINFO" do - it "loads from custom source" do + it "loads from custom directory" do with_zoneinfo(File.join(__DIR__, "..", "data", "zoneinfo")) do location = Location.load("Foo/Bar") location.name.should eq "Foo/Bar" end + end + it "loads from custom zipfile" do with_zoneinfo(ZONEINFO_ZIP) do location = Location.load("Asia/Jerusalem") location.not_nil!.name.should eq "Asia/Jerusalem" @@ -122,7 +123,6 @@ class Time::Location location = Location::UTC location.name.should eq "UTC" - location.unspecified?.should be_false location.utc?.should be_true location.fixed?.should be_true @@ -137,21 +137,6 @@ class Time::Location zone.dst?.should be_false end - it "UNSPECIFIED" do - location = Location::UNSPECIFIED - location.name.should eq "UNSPECIFIED" - - location.unspecified?.should be_true - location.utc?.should be_false - location.fixed?.should be_false - location.local?.should be_false - - zone = location.lookup(Time.now) - zone.name.should eq "UNSPECIFIED" - zone.offset.should eq 0 - zone.dst?.should be_false - end - it ".local" do with_env("TZ", nil) do Location.local.name.should eq "Local" @@ -171,7 +156,6 @@ class Time::Location location.zones.should eq [Zone.new("Fixed", 1800, false)] location.transitions.size.should eq 0 - location.unspecified?.should be_false location.utc?.should be_false location.fixed?.should be_true location.local?.should be_false diff --git a/spec/std/time/time_spec.cr b/spec/std/time/time_spec.cr index 169004f4aa0b..a96ba7d1159f 100644 --- a/spec/std/time/time_spec.cr +++ b/spec/std/time/time_spec.cr @@ -7,13 +7,17 @@ def Time.expect_invalid end end +private def parse_time(format, string) + Time.parse(format, string, Time::Location.local) +end + describe Time do it "initialize" do t1 = Time.new 2002, 2, 25 t1.year.should eq(2002) t1.month.should eq(2) t1.day.should eq(25) - t1.floating?.should be_true + t1.local?.should be_true t2 = Time.new 2002, 2, 25, 15, 25, 13, nanosecond: 8 t2.year.should eq(2002) @@ -23,7 +27,7 @@ describe Time do t2.minute.should eq(25) t2.second.should eq(13) t2.nanosecond.should eq(8) - t2.floating?.should be_true + t2.local?.should be_true end it "initialize max" do @@ -382,17 +386,6 @@ describe Time do t.to_s("%6N").to_s.should eq("006000") t.to_s("%9N").to_s.should eq("006000000") - floating = Time.new(2017, 11, 24, 13, 5, 6, location: Time::Location::UNSPECIFIED) - expect_raises(Time::FloatingTimeConversionError) do - floating.to_s("%z") - end - expect_raises(Time::FloatingTimeConversionError) do - floating.to_s("%:z") - end - expect_raises(Time::FloatingTimeConversionError) do - floating.to_s("%::z") - end - Time.utc_now.to_s("%z").should eq("+0000") Time.utc_now.to_s("%:z").should eq("+00:00") Time.utc_now.to_s("%::z").should eq("+00:00:00") @@ -457,7 +450,7 @@ describe Time do end it "parses empty" do - t = Time.parse("", "") + t = Time.parse("", "", Time::Location.local) t.year.should eq(1) t.month.should eq(1) t.day.should eq(1) @@ -465,61 +458,71 @@ describe Time do t.minute.should eq(0) t.second.should eq(0) t.millisecond.should eq(0) - t.floating?.should be_true - end - - it { Time.parse("2014", "%Y").year.should eq(2014) } - it { Time.parse("19", "%C").year.should eq(1900) } - it { Time.parse("14", "%y").year.should eq(2014) } - it { Time.parse("09", "%m").month.should eq(9) } - it { Time.parse(" 9", "%_m").month.should eq(9) } - it { Time.parse("9", "%-m").month.should eq(9) } - it { Time.parse("February", "%B").month.should eq(2) } - it { Time.parse("March", "%B").month.should eq(3) } - it { Time.parse("MaRcH", "%B").month.should eq(3) } - it { Time.parse("MaR", "%B").month.should eq(3) } - it { Time.parse("MARCH", "%^B").month.should eq(3) } - it { Time.parse("Mar", "%b").month.should eq(3) } - it { Time.parse("Mar", "%^b").month.should eq(3) } - it { Time.parse("MAR", "%^b").month.should eq(3) } - it { Time.parse("MAR", "%h").month.should eq(3) } - it { Time.parse("MAR", "%^h").month.should eq(3) } - it { Time.parse("2", "%d").day.should eq(2) } - it { Time.parse("02", "%d").day.should eq(2) } - it { Time.parse("02", "%-d").day.should eq(2) } - it { Time.parse(" 2", "%e").day.should eq(2) } - it { Time.parse("9", "%H").hour.should eq(9) } - it { Time.parse(" 9", "%k").hour.should eq(9) } - it { Time.parse("09", "%I").hour.should eq(9) } - it { Time.parse(" 9", "%l").hour.should eq(9) } - it { Time.parse("9pm", "%l%p").hour.should eq(21) } - it { Time.parse("9PM", "%l%P").hour.should eq(21) } - it { Time.parse("09", "%M").minute.should eq(9) } - it { Time.parse("09", "%S").second.should eq(9) } - it { Time.parse("123", "%L").millisecond.should eq(123) } - it { Time.parse("1", "%L").millisecond.should eq(100) } - it { Time.parse("000000321", "%N").nanosecond.should eq(321) } - it { Time.parse("321", "%N").nanosecond.should eq(321000000) } - it { Time.parse("321999", "%3N").nanosecond.should eq(321000000) } - it { Time.parse("321", "%6N").nanosecond.should eq(321000000) } - it { Time.parse("000321999", "%6N").nanosecond.should eq(321000) } - it { Time.parse("000000321999", "%9N").nanosecond.should eq(321) } - it { Time.parse("321", "%9N").nanosecond.should eq(321000000) } - it { Time.parse("3214569879999", "%N").nanosecond.should eq(321456987) } - it { Time.parse("Fri Oct 31 23:00:24 2014", "%c").to_s.should eq("2014-10-31 23:00:24") } - it { Time.parse("10/31/14", "%D").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("10/31/69", "%D").to_s.should eq("1969-10-31 00:00:00") } - it { Time.parse("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("10/31/14", "%x").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("10:11:12", "%X").to_s.should eq("0001-01-01 10:11:12") } - it { Time.parse("11:14:01 PM", "%r").to_s.should eq("0001-01-01 23:14:01") } - it { Time.parse("11:14", "%R").to_s.should eq("0001-01-01 11:14:00") } - it { Time.parse("11:12:13", "%T").to_s.should eq("0001-01-01 11:12:13") } - it { Time.parse("This was done on Friday, October 31, 2014", "This was done on %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("今は Friday, October 31, 2014", "今は %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00") } - it { Time.parse("epoch: 1459864667", "epoch: %s").epoch.should eq(1459864667) } - it { Time.parse("epoch: -1459864667", "epoch: %s").epoch.should eq(-1459864667) } + t.local?.should be_true + end + + it "parse fails without time zone" do + expect_raises(Time::Format::Error, "no default location provided") do + Time.parse("2017-12-01 20:15:13", "%F %T") + end + Time.parse("2017-12-01 20:15:13", "%F %T", Time::Location.local).to_s("%F %T").should eq "2017-12-01 20:15:13" + Time.parse("2017-12-01 20:15:13 +01:00", "%F %T %:z").to_s("%F %T %:z").should eq "2017-12-01 20:15:13 +01:00" + end + + it "parses" do + parse_time("2014", "%Y").year.should eq(2014) + parse_time("19", "%C").year.should eq(1900) + parse_time("14", "%y").year.should eq(2014) + parse_time("09", "%m").month.should eq(9) + parse_time(" 9", "%_m").month.should eq(9) + parse_time("9", "%-m").month.should eq(9) + parse_time("February", "%B").month.should eq(2) + parse_time("March", "%B").month.should eq(3) + parse_time("MaRcH", "%B").month.should eq(3) + parse_time("MaR", "%B").month.should eq(3) + parse_time("MARCH", "%^B").month.should eq(3) + parse_time("Mar", "%b").month.should eq(3) + parse_time("Mar", "%^b").month.should eq(3) + parse_time("MAR", "%^b").month.should eq(3) + parse_time("MAR", "%h").month.should eq(3) + parse_time("MAR", "%^h").month.should eq(3) + parse_time("2", "%d").day.should eq(2) + parse_time("02", "%d").day.should eq(2) + parse_time("02", "%-d").day.should eq(2) + parse_time(" 2", "%e").day.should eq(2) + parse_time("9", "%H").hour.should eq(9) + parse_time(" 9", "%k").hour.should eq(9) + parse_time("09", "%I").hour.should eq(9) + parse_time(" 9", "%l").hour.should eq(9) + parse_time("9pm", "%l%p").hour.should eq(21) + parse_time("9PM", "%l%P").hour.should eq(21) + parse_time("09", "%M").minute.should eq(9) + parse_time("09", "%S").second.should eq(9) + parse_time("123", "%L").millisecond.should eq(123) + parse_time("1", "%L").millisecond.should eq(100) + parse_time("000000321", "%N").nanosecond.should eq(321) + parse_time("321", "%N").nanosecond.should eq(321000000) + parse_time("321999", "%3N").nanosecond.should eq(321000000) + parse_time("321", "%6N").nanosecond.should eq(321000000) + parse_time("000321999", "%6N").nanosecond.should eq(321000) + parse_time("000000321999", "%9N").nanosecond.should eq(321) + parse_time("321", "%9N").nanosecond.should eq(321000000) + parse_time("3214569879999", "%N").nanosecond.should eq(321456987) + parse_time("Fri Oct 31 23:00:24 2014", "%c").to_s.should eq("2014-10-31 23:00:24") + parse_time("10/31/14", "%D").to_s.should eq("2014-10-31 00:00:00") + parse_time("10/31/69", "%D").to_s.should eq("1969-10-31 00:00:00") + parse_time("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00") + parse_time("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00") + parse_time("10/31/14", "%x").to_s.should eq("2014-10-31 00:00:00") + parse_time("10:11:12", "%X").to_s.should eq("0001-01-01 10:11:12") + parse_time("11:14:01 PM", "%r").to_s.should eq("0001-01-01 23:14:01") + parse_time("11:14", "%R").to_s.should eq("0001-01-01 11:14:00") + parse_time("11:12:13", "%T").to_s.should eq("0001-01-01 11:12:13") + parse_time("This was done on Friday, October 31, 2014", "This was done on %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00") + parse_time("今は Friday, October 31, 2014", "今は %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00") + parse_time("epoch: 1459864667", "epoch: %s").epoch.should eq(1459864667) + parse_time("epoch: -1459864667", "epoch: %s").epoch.should eq(-1459864667) + end it "parses timezone" do patterns = {"%z", "%:z", "%::z"} @@ -529,7 +532,6 @@ describe Time do time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true - time.incremental?.should be_true end {"-0000", "-00:00", "-00:00:00"}.zip(patterns) do |string, pattern| @@ -537,7 +539,6 @@ describe Time do time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true - time.incremental?.should be_true end {"-0200", "-02:00", "-02:00:00"}.zip(patterns) do |string, pattern| @@ -545,7 +546,6 @@ describe Time do time.offset.should eq -2 * 3600 time.utc?.should be_false time.location.fixed?.should be_true - time.incremental?.should be_true end {"Z", "Z", "Z"}.zip(patterns) do |string, pattern| @@ -553,7 +553,6 @@ describe Time do time.offset.should eq 0 time.utc?.should be_true time.location.fixed?.should be_true - time.incremental?.should be_true end {"UTC", "UTC", "UTC"}.zip(patterns) do |string, pattern| @@ -561,14 +560,12 @@ describe Time do time.offset.should eq 0 time.utc?.should be_true time.location.fixed?.should be_true - time.incremental?.should be_true end time = Time.parse("+04:12:39", "%::z") time.offset.should eq 4 * 3600 + 12 * 60 + 39 time.utc?.should be_false time.location.fixed?.should be_true - time.incremental?.should be_true end # TODO %Z @@ -597,7 +594,6 @@ describe Time do it do time = Time.parse("2014-10-31 10:11:12 -06:00 hi", "%F %T %z hi") - time.incremental?.should be_true time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 @@ -606,7 +602,6 @@ describe Time do it do time = Time.parse("2014-10-31 10:11:12 +05:00 hi", "%F %T %z hi") - time.incremental?.should be_true time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq 5 * 3600 @@ -615,7 +610,6 @@ describe Time do it do time = Time.parse("2014-10-31 10:11:12 -06:00:00 hi", "%F %T %z hi") - time.incremental?.should be_true time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 @@ -624,7 +618,6 @@ describe Time do it do time = Time.parse("2014-10-31 10:11:12 -060000 hi", "%F %T %z hi") - time.incremental?.should be_true time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 @@ -672,20 +665,20 @@ describe Time do end it "parses discarding additional decimals" do - time = Time.parse("2016-09-09T17:03:28.456789123999+01:00", "%FT%T.%3N%z").to_utc + time = Time.parse("2016-09-09T17:03:28.456789123999", "%FT%T.%3N", Time::Location::UTC) time.nanosecond.should eq(456000000) - time = Time.parse("2016-09-09T17:03:28.456789123999+01:00", "%FT%T.%6N%z").to_utc + time = Time.parse("2016-09-09T17:03:28.456789123999", "%FT%T.%6N", Time::Location::UTC) time.nanosecond.should eq(456789000) - time = Time.parse("2016-09-09T17:03:28.456789123999+01:00", "%FT%T.%9N%z").to_utc + time = Time.parse("2016-09-09T17:03:28.456789123990", "%FT%T.%9N", Time::Location::UTC) time.nanosecond.should eq(456789123) - time = Time.parse("2016-09-09T17:03:28.456789123999999+01:00", "%FT%T.%N%z").to_utc - time.to_s.should eq("2016-09-09 16:03:28 UTC") + time = Time.parse("2016-09-09T17:03:28.456789123999999+01:00", "%FT%T.%N%z") + time.to_s.should eq("2016-09-09 17:03:28 +01:00") time.nanosecond.should eq(456789123) - time = Time.parse("4567892016-09-09T17:03:28+01:00", "%6N%FT%T%z").to_utc + time = Time.parse("4567892016-09-09T17:03:28", "%6N%FT%T", Time::Location::UTC) time.year.should eq(2016) time.nanosecond.should eq(456789000) end @@ -702,35 +695,35 @@ describe Time do end it "parses the correct amount of digits (#853)" do - time = Time.parse("20150624", "%Y%m%d") + time = Time.parse("20150624", "%Y%m%d", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(24) end it "parses month blank padded" do - time = Time.parse("2015 624", "%Y%_m%d") + time = Time.parse("2015 624", "%Y%_m%d", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(24) end it "parses day of month blank padded" do - time = Time.parse("201506 4", "%Y%m%e") + time = Time.parse("201506 4", "%Y%m%e", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(4) end it "parses hour 24 blank padded" do - time = Time.parse(" 31112", "%k%M%S") + time = Time.parse(" 31112", "%k%M%S", Time::Location::UTC) time.hour.should eq(3) time.minute.should eq(11) time.second.should eq(12) end it "parses hour 12 blank padded" do - time = Time.parse(" 31112", "%l%M%S") + time = Time.parse(" 31112", "%l%M%S", Time::Location::UTC) time.hour.should eq(3) time.minute.should eq(11) time.second.should eq(12) @@ -870,34 +863,10 @@ describe Time do time2.should eq(time1) time2.location.should eq(location2) end - - it "works with floating" do - location = Time::Location.fixed(3611) - time1 = Time.new(2017, 11, 24, 15, 47) - time1.floating?.should be_true - - time2 = time1.in(location) - - # Both could be possible... handling of floating time is not clear - # time2.should_not eq(time1) - # (time2 + 3611.seconds).to_floating.should eq time1 - time2.should eq(time1) - (time2.to_utc + 3611.seconds).should eq time1 - - time2.location.should eq(location) - time2.floating?.should be_false - - time_utc = time1.to_utc - time_utc.should eq time1 - (time2 - time_utc).should eq -3611.seconds - end end it "#to_s" do with_zoneinfo do - time = Time.new(2017, 11, 25, 22, 6, 17, location: Time::Location::UNSPECIFIED) - time.to_s.should eq "2017-11-25 22:06:17" - time = Time.new(2017, 11, 25, 22, 6, 17, location: Time::Location::UTC) time.to_s.should eq "2017-11-25 22:06:17 UTC" diff --git a/src/time.cr b/src/time.cr index 34409d211592..1b37ab155ad7 100644 --- a/src/time.cr +++ b/src/time.cr @@ -4,7 +4,7 @@ end require "./time/location" require "crystal/system/time" -# `Time` represents an instance in time. Here are some examples: +# `Time` represents an instance in incremental time. Here are some examples: # # ### Basic Usage # @@ -60,9 +60,6 @@ require "crystal/system/time" # span.hours # => 1 # ``` struct Time - class FloatingTimeConversionError < Exception - end - include Comparable(self) # :nodoc: @@ -165,7 +162,7 @@ struct Time new(seconds: seconds, nanoseconds: nanoseconds, location: location) end - def self.new(year, month, day, hour = 0, minute = 0, second = 0, *, nanosecond = 0, location = Location::UNSPECIFIED) + def self.new(year, month, day, hour = 0, minute = 0, second = 0, *, nanosecond = 0, location = Location.local) unless 1 <= year <= 9999 && 1 <= month <= 12 && 1 <= day <= Time.days_in_month(year, month) && @@ -192,7 +189,7 @@ struct Time {% unless flag?(:win32) %} # :nodoc: - def self.new(time : LibC::Timespec, kind = Location::UNSPECIFIED) + def self.new(time : LibC::Timespec, kind = Location.local) seconds = UNIX_SECONDS + time.tv_sec nanoseconds = time.tv_nsec.to_i new(seconds: seconds, nanoseconds: nanoseconds, location: location) @@ -240,11 +237,6 @@ struct Time new(seconds: seconds, nanoseconds: nanoseconds, location: Location::UTC) end - # Returns a new `Time` instance at the specified time in local time zone. - def self.local(year, month, day, hour = 0, minute = 0, second = 0, *, nanosecond = 0) : Time - new(year, month, day, hour, minute, second, nanosecond: nanosecond, location: Location.local) - end - def clone : self self end @@ -317,14 +309,10 @@ struct Time # # The amount can be negative if `self` is a `Time` that happens before *other*. def -(other : Time) : Time::Span - if floating? != other.floating? - to_floating - other.to_floating - else - Span.new( - seconds: total_seconds - other.total_seconds, - nanoseconds: nanosecond - other.nanosecond, - ) - end + Span.new( + seconds: total_seconds - other.total_seconds, + nanoseconds: nanosecond - other.nanosecond, + ) end # Returns the current time in the time zone currently observed in *location*, @@ -428,45 +416,17 @@ struct Time location.local? end - # Returns `true` if this time is not tied to a specific time zone. - # - # Applications that work with floating times need to avoid pitfalls that - # can arise from implicit conversion to incremental time values or the - # improper use of time zones when displaying or processing a floating time - # value. - # - # An indicator for a floating time is that `#location` equals `Location::UNSPECIFIED`. - def floating? : Bool - location.unspecified? - end - - # Returns `true` if this time is tied to a specific time zone (including - # `UTC`) and thus represents a specific instance in incremental time. - # - # This is the inverse of `#floating?`. - def incremental? : Bool - !floating? - end - def <=>(other : self) - if floating? != other.floating? - to_floating <=> other.to_floating - else - cmp = total_seconds <=> other.total_seconds - cmp = nanosecond <=> other.nanosecond if cmp == 0 - cmp - end + cmp = total_seconds <=> other.total_seconds + cmp = nanosecond <=> other.nanosecond if cmp == 0 + cmp end def ==(other : self) - if floating? != other.floating? - to_floating == other.to_floating - else - total_seconds == other.total_seconds && nanosecond == other.nanosecond - end + total_seconds == other.total_seconds && nanosecond == other.nanosecond end - def_hash total_seconds, nanosecond, floating? + def_hash total_seconds, nanosecond # Returns how many days this *month* (`1..12`) of this *year* has (28, 29, 30 or 31). # @@ -510,7 +470,7 @@ struct Time case when utc? to_s "%F %T UTC", io - when floating? + when local? to_s "%F %T", io else if offset % 60 == 0 @@ -545,7 +505,7 @@ struct Time # ``` # Time.parse("2016-04-05", "%F") # => 2016-04-05 00:00:00 # ``` - def self.parse(time : String, pattern : String, location = Location::UNSPECIFIED) : Time + def self.parse(time : String, pattern : String, location = nil) : Time Format.new(pattern, location).parse(time) end @@ -581,19 +541,11 @@ struct Time end def in(location : Location) : Time - if floating? - Time.new( - seconds: total_seconds - Time.zone_offset_at(total_seconds, location), - nanoseconds: nanosecond, - location: location - ) - else - Time.new( - seconds: total_seconds, - nanoseconds: nanosecond, - location: location - ) - end + Time.new( + seconds: total_seconds, + nanoseconds: nanosecond, + location: location + ) end # Returns a copy of this `Time` converted to UTC. @@ -617,18 +569,6 @@ struct Time end end - def to_floating : Time - if floating? - self - else - Time.new( - seconds: offset_seconds, - nanoseconds: nanosecond, - location: Location::UNSPECIFIED - ) - end - end - private macro def_at_beginning(interval) # Returns the time when the {{interval.id}} that contains `self` starts. def at_beginning_of_{{interval.id}} : Time diff --git a/src/time/format.cr b/src/time/format.cr index faed718b1db4..7fb185ad7e4c 100644 --- a/src/time/format.cr +++ b/src/time/format.cr @@ -67,7 +67,7 @@ struct Time::Format # Creates a new `Time::Format` with the given *pattern*. The given time # *location* will be used when parsing a `Time` and no time zone is found in it. - def initialize(@pattern : String, @location : Location = Location::UNSPECIFIED) + def initialize(@pattern : String, @location : Location? = nil) end # Parses a string into a `Time`. diff --git a/src/time/format/formatter.cr b/src/time/format/formatter.cr index 075f898623bb..077eb035f969 100644 --- a/src/time/format/formatter.cr +++ b/src/time/format/formatter.cr @@ -148,8 +148,6 @@ struct Time::Format end def time_zone(with_seconds = false) - raise FloatingTimeConversionError.new if time.floating? - negative, hours, minutes, seconds = local_time_zone_info io << (negative ? "-" : "+") io << "0" if hours < 10 @@ -163,8 +161,6 @@ struct Time::Format end def time_zone_colon(with_seconds = false) - raise FloatingTimeConversionError.new if time.floating? - negative, hours, minutes, seconds = local_time_zone_info io << (negative ? "-" : "+") io << "0" if hours < 10 diff --git a/src/time/format/parser.cr b/src/time/format/parser.cr index 8579bc62f841..6b23fd1a60e4 100644 --- a/src/time/format/parser.cr +++ b/src/time/format/parser.cr @@ -18,16 +18,19 @@ struct Time::Format @pm = false end - def time(location : Location = Location::UNSPECIFIED) + def time(location : Location? = nil) @hour += 12 if @pm - time_location = @location || location - if epoch = @epoch return Time.epoch(epoch) end - Time.new @year, @month, @day, @hour, @minute, @second, nanosecond: @nanosecond, location: time_location + location = @location || location + if location.nil? + raise "Time format did not include time zone and no default location provided" + end + + Time.new @year, @month, @day, @hour, @minute, @second, nanosecond: @nanosecond, location: location end def year diff --git a/src/time/location.cr b/src/time/location.cr index fe526a8aefe2..c17063515173 100644 --- a/src/time/location.cr +++ b/src/time/location.cr @@ -3,7 +3,7 @@ require "./location/loader" # `Location` represents a specific time zone. # # It can be either a time zone from the IANA Time Zone database, -# a fixed offset, `UTC` or `UNSPECIFIED`. +# a fixed offset, or `UTC`. # # Creating a location from timezone data: # ``` @@ -26,9 +26,8 @@ require "./location/loader" # # There are also a few special conversions: # ``` -# time.to_utc # == time.in(Location::UTC) -# time.to_local # == time.in(Location.local) -# time.to_floating # == time.in(Location::UNSPECIFIED) +# time.to_utc # == time.in(Location::UTC) +# time.to_local # == time.in(Location.local) # ``` class Time::Location class InvalidLocationNameError < Exception @@ -46,8 +45,7 @@ class Time::Location end struct Zone - UTC = new "UTC", 0, false - UNSPECIFIED = new "UNSPECIFIED", 0, false + UTC = new "UTC", 0, false getter name : String getter offset : Int32 @@ -86,13 +84,6 @@ class Time::Location # Describes the Coordinated Universal Time (UTC). UTC = new "UTC", [Zone::UTC] - # An unspecified `Location` that is used for floating time instances - # which are not tied to a specific time zone. - # - # This is a special case, as instances with this location cannot - # be directly compared to instances with incrementing time. - UNSPECIFIED = new "UNSPECIFIED", [Zone::UNSPECIFIED] - property name : String property zones : Array(Zone) @@ -283,16 +274,8 @@ class Time::Location self == Location.local end - # Returns `true` if this location equals to `UNSPECIFIED`. - # - # An unspecified location is used for floating time instances - # which are not tied to a specific time zone. - def unspecified? : Bool - self == UNSPECIFIED - end - # Returns `true` if this location has a fixed offset. def fixed? - !unspecified? && zones.size <= 1 + zones.size <= 1 end end