From 7d24b5c0ef2b5269242972a13d5e00d3006dc04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Thu, 23 Nov 2017 17:51:14 +0100 Subject: [PATCH 1/3] Add Time.utc to easily create a UTC time instance Creating a UTC time instance is fairly commmon and should not bother with internals instead have a simple API for this. This fits nicely with already existing `Time.utc_now`. --- spec/std/http/formdata/builder_spec.cr | 2 +- spec/std/http/formdata_spec.cr | 6 ++--- spec/std/http/http_spec.cr | 2 +- spec/std/json/serialization_spec.cr | 4 +-- spec/std/time/time_spec.cr | 8 +++--- spec/std/yaml/any_spec.cr | 4 +-- spec/std/yaml/schema/core_spec.cr | 36 +++++++++++++------------- spec/std/yaml/serialization_spec.cr | 8 +++--- src/time.cr | 26 ++++++++++++++----- src/yaml/schema/core/time_parser.cr | 2 +- 10 files changed, 55 insertions(+), 43 deletions(-) diff --git a/spec/std/http/formdata/builder_spec.cr b/spec/std/http/formdata/builder_spec.cr index 294c192c7236..d760b8c49438 100644 --- a/spec/std/http/formdata/builder_spec.cr +++ b/spec/std/http/formdata/builder_spec.cr @@ -9,7 +9,7 @@ describe HTTP::FormData::Builder do g.field("baz", "qux", HTTP::Headers{"X-Testing" => "headers"}) body = IO::Memory.new "file content" - time = Time.new(2016, 1, 1, 12, 0, 0, kind: Time::Kind::Utc) + time = Time.utc(2016, 1, 1, 12, 0, 0) metadata = HTTP::FormData::FileMetadata.new("filename.txt \"", time, time, time, 12_u64) headers = HTTP::Headers{"Foo" => "Bar", "Baz" => "Qux"} g.file("file-test", body, metadata, headers) diff --git a/spec/std/http/formdata_spec.cr b/spec/std/http/formdata_spec.cr index 9dc800205456..f879a727640a 100644 --- a/spec/std/http/formdata_spec.cr +++ b/spec/std/http/formdata_spec.cr @@ -69,9 +69,9 @@ describe HTTP::FormData do name.should eq("foo") meta.filename.should eq(%q(foo"\bar baz\)) - meta.creation_time.should eq(Time.new(1997, 2, 12, 21, 29, 51, nanosecond: 0, kind: Time::Kind::Utc)) - meta.modification_time.should eq(Time.new(1997, 2, 12, 21, 29, 51, nanosecond: 0, kind: Time::Kind::Utc)) - meta.read_time.should eq(Time.new(1997, 2, 12, 21, 29, 51, nanosecond: 0, kind: Time::Kind::Utc)) + meta.creation_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0)) + meta.modification_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0)) + meta.read_time.should eq(Time.utc(1997, 2, 12, 21, 29, 51, nanosecond: 0)) meta.size.should eq(432334) end end diff --git a/spec/std/http/http_spec.cr b/spec/std/http/http_spec.cr index e1bdb0921c4d..120b830cf889 100644 --- a/spec/std/http/http_spec.cr +++ b/spec/std/http/http_spec.cr @@ -39,7 +39,7 @@ describe HTTP do describe "generates RFC 1123" do it "without time zone" do - time = Time.new(1994, 11, 6, 8, 49, 37, nanosecond: 0, kind: Time::Kind::Utc) + time = Time.utc(1994, 11, 6, 8, 49, 37, nanosecond: 0) HTTP.rfc1123_date(time).should eq("Sun, 06 Nov 1994 08:49:37 GMT") end diff --git a/spec/std/json/serialization_spec.cr b/spec/std/json/serialization_spec.cr index 9d14af9d65ca..39786b13d677 100644 --- a/spec/std/json/serialization_spec.cr +++ b/spec/std/json/serialization_spec.cr @@ -137,7 +137,7 @@ describe "JSON serialization" do end it "deserializes Time" do - Time.from_json(%("2016-11-16T09:55:48-0300")).to_utc.should eq(Time.new(2016, 11, 16, 12, 55, 48, kind: Time::Kind::Utc)) + Time.from_json(%("2016-11-16T09:55:48-0300")).to_utc.should eq(Time.utc(2016, 11, 16, 12, 55, 48)) end describe "parse exceptions" do @@ -312,7 +312,7 @@ describe "JSON serialization" do end it "does for time" do - Time.new(2016, 11, 16, 12, 55, 48, kind: Time::Kind::Utc).to_json.should eq(%("2016-11-16T12:55:48+0000")) + Time.utc(2016, 11, 16, 12, 55, 48).to_json.should eq(%("2016-11-16T12:55:48+0000")) end end end diff --git a/spec/std/time/time_spec.cr b/spec/std/time/time_spec.cr index bb3bf3ea42e4..94ce25959298 100644 --- a/spec/std/time/time_spec.cr +++ b/spec/std/time/time_spec.cr @@ -49,14 +49,14 @@ describe Time do it "initialize with .epoch" do seconds = 1439404155 time = Time.epoch(seconds) - time.should eq(Time.new(2015, 8, 12, 18, 29, 15, kind: Time::Kind::Utc)) + time.should eq(Time.utc(2015, 8, 12, 18, 29, 15)) time.epoch.should eq(seconds) end it "initialize with .epoch_ms" do milliseconds = 1439404155000 time = Time.epoch_ms(milliseconds) - time.should eq(Time.new(2015, 8, 12, 18, 29, 15, kind: Time::Kind::Utc)) + time.should eq(Time.utc(2015, 8, 12, 18, 29, 15)) time.epoch_ms.should eq(milliseconds) end @@ -246,7 +246,7 @@ describe Time do end it "gets unix epoch seconds" do - t1 = Time.new 2014, 10, 30, 21, 18, 13, nanosecond: 0, kind: Time::Kind::Utc + t1 = Time.utc 2014, 10, 30, 21, 18, 13, nanosecond: 0 t1.epoch.should eq(1414703893) t1.epoch_f.should be_close(1414703893, 1e-01) end @@ -369,7 +369,7 @@ describe Time do t.to_s("%Y-%m-hello").should eq("2014-01-hello") - t = Time.new 2014, 1, 2, 3, 4, 5, nanosecond: 6, kind: Time::Kind::Utc + t = Time.utc 2014, 1, 2, 3, 4, 5, nanosecond: 6 t.to_s("%s").should eq("1388631845") end diff --git a/spec/std/yaml/any_spec.cr b/spec/std/yaml/any_spec.cr index 78d307136038..0b7ba1b4814c 100644 --- a/spec/std/yaml/any_spec.cr +++ b/spec/std/yaml/any_spec.cr @@ -66,10 +66,10 @@ describe YAML::Any do it "gets time" do value = YAML.parse("2010-01-02").as_time - value.should eq(Time.new(2010, 1, 2, kind: Time::Kind::Utc)) + value.should eq(Time.utc(2010, 1, 2)) value = YAML.parse("2010-01-02").as_time? - value.should eq(Time.new(2010, 1, 2, kind: Time::Kind::Utc)) + value.should eq(Time.utc(2010, 1, 2)) value = YAML.parse("hello").as_time? value.should be_nil diff --git a/spec/std/yaml/schema/core_spec.cr b/spec/std/yaml/schema/core_spec.cr index 0cb295c53650..09aed4b1565d 100644 --- a/spec/std/yaml/schema/core_spec.cr +++ b/spec/std/yaml/schema/core_spec.cr @@ -109,23 +109,23 @@ describe YAML::Schema::Core do it_parses_scalar "-0x123abc", -0x123abc # time - it_parses_scalar "2002-12-14", Time.new(2002, 12, 14, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2", Time.new(2002, 1, 2, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12", Time.new(2002, 1, 2, 10, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2 10:11:12", Time.new(2002, 1, 2, 10, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2 1:11:12", Time.new(2002, 1, 2, 1, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12.3", Time.new(2002, 1, 2, 10, 11, 12, nanosecond: 300_000_000, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12.34", Time.new(2002, 1, 2, 10, 11, 12, nanosecond: 340_000_000, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12.345", Time.new(2002, 1, 2, 10, 11, 12, nanosecond: 345_000_000, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12.3456", Time.new(2002, 1, 2, 10, 11, 12, nanosecond: 345_600_000, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12Z", Time.new(2002, 1, 2, 10, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 Z", Time.new(2002, 1, 2, 10, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 +3", Time.new(2002, 1, 2, 7, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 +03:00", Time.new(2002, 1, 2, 7, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 -03:00", Time.new(2002, 1, 2, 13, 11, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 -03:31", Time.new(2002, 1, 2, 13, 42, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12-03:31", Time.new(2002, 1, 2, 13, 42, 12, kind: Time::Kind::Utc) - it_parses_scalar "2002-1-2T10:11:12 +0300", Time.new(2002, 1, 2, 7, 11, 12, kind: Time::Kind::Utc) + it_parses_scalar "2002-12-14", Time.utc(2002, 12, 14) + it_parses_scalar "2002-1-2", Time.utc(2002, 1, 2) + it_parses_scalar "2002-1-2T10:11:12", Time.utc(2002, 1, 2, 10, 11, 12) + it_parses_scalar "2002-1-2 10:11:12", Time.utc(2002, 1, 2, 10, 11, 12) + it_parses_scalar "2002-1-2 1:11:12", Time.utc(2002, 1, 2, 1, 11, 12) + it_parses_scalar "2002-1-2T10:11:12.3", Time.utc(2002, 1, 2, 10, 11, 12, nanosecond: 300_000_000) + it_parses_scalar "2002-1-2T10:11:12.34", Time.utc(2002, 1, 2, 10, 11, 12, nanosecond: 340_000_000) + it_parses_scalar "2002-1-2T10:11:12.345", Time.utc(2002, 1, 2, 10, 11, 12, nanosecond: 345_000_000) + it_parses_scalar "2002-1-2T10:11:12.3456", Time.utc(2002, 1, 2, 10, 11, 12, nanosecond: 345_600_000) + it_parses_scalar "2002-1-2T10:11:12Z", Time.utc(2002, 1, 2, 10, 11, 12) + it_parses_scalar "2002-1-2T10:11:12 Z", Time.utc(2002, 1, 2, 10, 11, 12) + it_parses_scalar "2002-1-2T10:11:12 +3", Time.utc(2002, 1, 2, 7, 11, 12) + it_parses_scalar "2002-1-2T10:11:12 +03:00", Time.utc(2002, 1, 2, 7, 11, 12) + it_parses_scalar "2002-1-2T10:11:12 -03:00", Time.utc(2002, 1, 2, 13, 11, 12) + it_parses_scalar "2002-1-2T10:11:12 -03:31", Time.utc(2002, 1, 2, 13, 42, 12) + it_parses_scalar "2002-1-2T10:11:12-03:31", Time.utc(2002, 1, 2, 13, 42, 12) + it_parses_scalar "2002-1-2T10:11:12 +0300", Time.utc(2002, 1, 2, 7, 11, 12) # invalid time it_parses_string "2002-34-45" @@ -197,6 +197,6 @@ describe YAML::Schema::Core do it_raises_on_parse "!!str [1]", "Expected SCALAR" # # !!timestamp - it_parses "!!timestamp 2010-01-02", Time.new(2010, 1, 2, kind: Time::Kind::Utc) + it_parses "!!timestamp 2010-01-02", Time.utc(2010, 1, 2) it_raises_on_parse "!!timestamp foo", "Invalid timestamp" end diff --git a/spec/std/yaml/serialization_spec.cr b/spec/std/yaml/serialization_spec.cr index dba41be57a50..fa5026a046f9 100644 --- a/spec/std/yaml/serialization_spec.cr +++ b/spec/std/yaml/serialization_spec.cr @@ -161,7 +161,7 @@ describe "YAML serialization" do end it "deserializes time" do - Time.from_yaml("2010-11-12").should eq(Time.new(2010, 11, 12, kind: Time::Kind::Utc)) + Time.from_yaml("2010-11-12").should eq(Time.utc(2010, 11, 12)) end it "deserializes bytes" do @@ -295,17 +295,17 @@ describe "YAML serialization" do end it "does for utc time" do - time = Time.new(2010, 11, 12, 1, 2, 3, kind: Time::Kind::Utc) + time = Time.utc(2010, 11, 12, 1, 2, 3) time.to_yaml.should eq("--- 2010-11-12 01:02:03\n...\n") end it "does for time at date" do - time = Time.new(2010, 11, 12, kind: Time::Kind::Utc) + time = Time.utc(2010, 11, 12) time.to_yaml.should eq("--- 2010-11-12\n...\n") end it "does for utc time with nanoseconds" do - time = Time.new(2010, 11, 12, 1, 2, 3, nanosecond: 456_000_000, kind: Time::Kind::Utc) + time = Time.utc(2010, 11, 12, 1, 2, 3, nanosecond: 456_000_000) time.to_yaml.should eq("--- 2010-11-12 01:02:03.456\n...\n") end diff --git a/src/time.cr b/src/time.cr index b0c6dbcb395c..9694adeb39ce 100644 --- a/src/time.cr +++ b/src/time.cr @@ -19,7 +19,10 @@ require "crystal/system/time" # Time.new(2016, 2, 15) # => 2016-02-15 00:00:00 # # # Specifying a time -# Time.new(2016, 2, 15, 10, 20, 30) # => 2016-02-15 10:20:30 UTC +# Time.new(2016, 2, 15, 10, 20, 30) # => 2016-02-15 10:20:30 +# +# # Creating a time instance in UTC +# Time.utc(2016, 2, 15, 10, 20, 30) # => 2016-02-15 10:20:30 UTC # ``` # # ### Formatting Time @@ -225,7 +228,7 @@ struct Time # Time.epoch(981173106) # => 2001-02-03 04:05:06 UTC # ``` def self.epoch(seconds : Int) : Time - new(seconds: UNIX_SECONDS + seconds, nanoseconds: 0, kind: Kind::Utc) + utc(seconds: UNIX_SECONDS + seconds, nanoseconds: 0) end # Returns a new `Time` instance that corresponds to the number @@ -239,7 +242,17 @@ struct Time milliseconds = milliseconds.to_i64 seconds = UNIX_SECONDS + (milliseconds / 1_000) nanoseconds = (milliseconds % 1000) * NANOSECONDS_PER_MILLISECOND - new(seconds: seconds, nanoseconds: nanoseconds.to_i, kind: Kind::Utc) + utc(seconds: seconds, nanoseconds: nanoseconds.to_i) + end + + # Returns a new `Time` instance at the specified time in UTC time zone. + def self.utc(year, month, day, hour = 0, minute = 0, second = 0, *, nanosecond = 0) : Time + new(year, month, day, hour, minute, second, nanosecond: nanosecond, kind: Kind::Utc) + end + + # Returns a new `Time` instance at the specified time in UTC time zone. + def self.utc(*, seconds : Int64, nanoseconds : Int32) : Time + new(seconds: seconds, nanoseconds: nanoseconds, kind: Kind::Utc) end def clone : self @@ -334,7 +347,7 @@ struct Time # Returns the current time in UTC time zone. def self.utc_now : Time seconds, nanoseconds = compute_seconds_and_nanoseconds - new(seconds: seconds, nanoseconds: nanoseconds, kind: Kind::Utc) + utc(seconds: seconds, nanoseconds: nanoseconds) end # Returns a copy of `self` with time-of-day components (hour, minute, ...) set to zero. @@ -539,10 +552,9 @@ struct Time if utc? self else - Time.new( + Time.utc( seconds: total_seconds - Time.compute_offset, - nanoseconds: nanosecond, - kind: Kind::Utc, + nanoseconds: nanosecond ) end end diff --git a/src/yaml/schema/core/time_parser.cr b/src/yaml/schema/core/time_parser.cr index 538eac32e27c..ad8eb794dbd3 100644 --- a/src/yaml/schema/core/time_parser.cr +++ b/src/yaml/schema/core/time_parser.cr @@ -192,7 +192,7 @@ struct YAML::Schema::Core::TimeParser end def new_time(*args, **named_args) - Time.new(*args, **named_args, kind: Time::Kind::Utc) + Time.utc(*args, **named_args) rescue nil end From 3006b61891495ed7fdc2b1bfb4fdc963e05aaa67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Thu, 23 Nov 2017 14:31:25 +0100 Subject: [PATCH 2/3] Use `Time#utc?` and `#local?` instead of comparing `#kind` --- spec/std/http/http_spec.cr | 4 ++-- spec/std/time/time_spec.cr | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/std/http/http_spec.cr b/spec/std/http/http_spec.cr index 120b830cf889..a0ab875255e5 100644 --- a/spec/std/http/http_spec.cr +++ b/spec/std/http/http_spec.cr @@ -27,13 +27,13 @@ describe HTTP do it "parses and is UTC (#2744)" do date = "Mon, 09 Sep 2011 23:36:00 GMT" parsed_time = HTTP.parse_time(date).not_nil! - parsed_time.kind.should eq(Time::Kind::Utc) + parsed_time.utc?.should be_true end it "parses and is local (#2744)" do date = "Mon, 09 Sep 2011 23:36:00 -0300" parsed_time = HTTP.parse_time(date).not_nil! - parsed_time.kind.should eq(Time::Kind::Local) + parsed_time.local?.should be_true parsed_time.to_utc.to_s.should eq("2011-09-10 02:36:00 UTC") end diff --git a/spec/std/time/time_spec.cr b/spec/std/time/time_spec.cr index 94ce25959298..3fa42e08d670 100644 --- a/spec/std/time/time_spec.cr +++ b/spec/std/time/time_spec.cr @@ -521,7 +521,7 @@ describe Time do it "can parse in UTC" do time = Time.parse("2014-10-31 11:12:13", "%F %T", Time::Kind::Utc) - time.kind.should eq(Time::Kind::Utc) + time.utc?.should be_true end it "at" do @@ -600,9 +600,9 @@ describe Time do it "preserves kind when adding" do time = Time.utc_now - time.kind.should eq(Time::Kind::Utc) + time.utc?.should be_true - (time + 5.minutes).kind.should eq(Time::Kind::Utc) + (time + 5.minutes).utc?.should be_true end it "asks for day name" do From 89d89c6264027a3a20687413696dac5d79dd6569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Fri, 24 Nov 2017 17:09:04 +0100 Subject: [PATCH 3/3] Convert intended usage of Time.new to Time.utc in specs --- spec/std/gzip/gzip_spec.cr | 2 +- spec/std/http/cookie_spec.cr | 10 +++++----- spec/std/http/http_spec.cr | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/std/gzip/gzip_spec.cr b/spec/std/gzip/gzip_spec.cr index 750fd91a6c0f..2cdd9ecc2bb1 100644 --- a/spec/std/gzip/gzip_spec.cr +++ b/spec/std/gzip/gzip_spec.cr @@ -5,7 +5,7 @@ describe Gzip do it "writes and reads to memory" do io = IO::Memory.new - time = Time.new(2016, 1, 2) + time = Time.utc(2016, 1, 2) os = 4_u8 extra = Bytes[1, 2, 3] name = "foo.txt" diff --git a/spec/std/http/cookie_spec.cr b/spec/std/http/cookie_spec.cr index c5a928fd00fc..a3e717de404e 100644 --- a/spec/std/http/cookie_spec.cr +++ b/spec/std/http/cookie_spec.cr @@ -97,7 +97,7 @@ module HTTP it "parses expires rfc1123" do cookie = parse_set_cookie("key=value; expires=Sun, 06 Nov 1994 08:49:37 GMT") - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) cookie.name.should eq("key") cookie.value.should eq("value") @@ -106,7 +106,7 @@ module HTTP it "parses expires rfc1036" do cookie = parse_set_cookie("key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT") - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) cookie.name.should eq("key") cookie.value.should eq("value") @@ -115,7 +115,7 @@ module HTTP it "parses expires ansi c" do cookie = parse_set_cookie("key=value; expires=Sun Nov 6 08:49:37 1994") - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) cookie.name.should eq("key") cookie.value.should eq("value") @@ -124,12 +124,12 @@ module HTTP it "parses expires ansi c, variant with zone" do cookie = parse_set_cookie("bla=; expires=Thu, 01 Jan 1970 00:00:00 -0000") - cookie.expires.should eq(Time.new(1970, 1, 1, 0, 0, 0)) + cookie.expires.should eq(Time.utc(1970, 1, 1, 0, 0, 0)) end it "parses full" do cookie = parse_set_cookie("key=value; path=/test; domain=www.example.com; HttpOnly; Secure; expires=Sun, 06 Nov 1994 08:49:37 GMT") - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) cookie.name.should eq("key") cookie.value.should eq("value") diff --git a/spec/std/http/http_spec.cr b/spec/std/http/http_spec.cr index a0ab875255e5..e29d4b7ae55f 100644 --- a/spec/std/http/http_spec.cr +++ b/spec/std/http/http_spec.cr @@ -3,24 +3,24 @@ require "http" describe HTTP do it "parses RFC 1123" do - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) HTTP.parse_time("Sun, 06 Nov 1994 08:49:37 GMT").should eq(time) end it "parses RFC 1123 without day name" do - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) HTTP.parse_time("06 Nov 1994 08:49:37 GMT").should eq(time) end it "parses RFC 1036" do - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) HTTP.parse_time("Sunday, 06-Nov-94 08:49:37 GMT").should eq(time) end it "parses ANSI C" do - time = Time.new(1994, 11, 6, 8, 49, 37) + time = Time.utc(1994, 11, 6, 8, 49, 37) HTTP.parse_time("Sun Nov 6 08:49:37 1994").should eq(time) - time2 = Time.new(1994, 11, 16, 8, 49, 37) + time2 = Time.utc(1994, 11, 16, 8, 49, 37) HTTP.parse_time("Sun Nov 16 08:49:37 1994").should eq(time2) end