From 381b01594a9cdaeb2f170a38e9c38508543b9662 Mon Sep 17 00:00:00 2001 From: Bart de Water <118401830+bdewater-thatch@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:28:08 -0400 Subject: [PATCH] Require offset when parsing RFC3339 RFC3339 requires a Z designator or explicit numeric offset. Reject offset-less timestamps instead of passing them to Time.new, which interprets them in local time. --- lib/time.rb | 2 +- test/test_time.rb | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/time.rb b/lib/time.rb index 40f954a..4d1a027 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -660,7 +660,7 @@ def rfc3339(time) [T\s] (\d\d):(\d\d):(\d\d) (\.\d+)? - (Z|[+-]\d\d(?::?\d\d)?)? + (Z|[+-]\d\d(?::?\d\d)?) \s*\z/ix _xmlschema(pattern, time) end diff --git a/test/test_time.rb b/test/test_time.rb index 200adc9..ac7a5b6 100644 --- a/test/test_time.rb +++ b/test/test_time.rb @@ -152,8 +152,6 @@ def subtest_xmlschema_alias(method) def subtest_xmlschema(method) assert_equal(Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600, Time.__send__(method, "1999-05-31T13:20:00-05:00")) - assert_equal(Time.local(2000, 1, 20, 12, 0, 0), - Time.__send__(method, "2000-01-20T12:00:00")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0), Time.__send__(method, "2000-01-20T12:00:00Z")) assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600, @@ -164,22 +162,10 @@ def subtest_xmlschema(method) Time.__send__(method, "2000-03-04T23:00:00+03:00")) assert_equal(Time.utc(2000, 3, 4, 20, 0, 0), Time.__send__(method, "2000-03-04T20:00:00Z")) - assert_equal(Time.local(2000, 1, 15, 0, 0, 0), - Time.__send__(method, "2000-01-15T00:00:00")) - assert_equal(Time.local(2000, 2, 15, 0, 0, 0), - Time.__send__(method, "2000-02-15T00:00:00")) - assert_equal(Time.local(2000, 1, 15, 12, 0, 0), - Time.__send__(method, "2000-01-15T12:00:00")) assert_equal(Time.utc(2000, 1, 16, 12, 0, 0), Time.__send__(method, "2000-01-16T12:00:00Z")) - assert_equal(Time.local(2000, 1, 1, 12, 0, 0), - Time.__send__(method, "2000-01-01T12:00:00")) assert_equal(Time.utc(1999, 12, 31, 23, 0, 0), Time.__send__(method, "1999-12-31T23:00:00Z")) - assert_equal(Time.local(2000, 1, 16, 12, 0, 0), - Time.__send__(method, "2000-01-16T12:00:00")) - assert_equal(Time.local(2000, 1, 16, 0, 0, 0), - Time.__send__(method, "2000-01-16T00:00:00")) assert_equal(Time.utc(2000, 1, 12, 12, 13, 14), Time.__send__(method, "2000-01-12T12:13:14Z")) assert_equal(Time.utc(2001, 4, 17, 19, 23, 17, 300000), @@ -187,6 +173,23 @@ def subtest_xmlschema(method) assert_equal(Time.utc(2000, 1, 2, 0, 0, 0), Time.__send__(method, "2000-01-01T24:00:00Z")) assert_raise(ArgumentError) { Time.__send__(method, "2000-01-01T00:00:00.+00:00") } + + local_times = [ + [Time.local(2000, 1, 20, 12, 0, 0), "2000-01-20T12:00:00"], + [Time.local(2000, 1, 15, 0, 0, 0), "2000-01-15T00:00:00"], + [Time.local(2000, 2, 15, 0, 0, 0), "2000-02-15T00:00:00"], + [Time.local(2000, 1, 15, 12, 0, 0), "2000-01-15T12:00:00"], + [Time.local(2000, 1, 1, 12, 0, 0), "2000-01-01T12:00:00"], + [Time.local(2000, 1, 16, 12, 0, 0), "2000-01-16T12:00:00"], + [Time.local(2000, 1, 16, 0, 0, 0), "2000-01-16T00:00:00"], + ] + local_times.each do |expected, time| + if method == :rfc3339 + assert_raise(ArgumentError) { Time.rfc3339(time) } + else + assert_equal(expected, Time.__send__(method, time)) + end + end end def subtest_xmlschema_encode(method)