diff options
author | Grzegorz Witek <arnvald.to@gmail.com> | 2015-11-15 01:04:28 +0800 |
---|---|---|
committer | Grzegorz Witek <arnvald.to@gmail.com> | 2016-01-22 09:25:28 +0800 |
commit | a3ddd5f1572f6ebf95f4c0a789413ee1b2ecbab5 (patch) | |
tree | 07ab0ac46ff35676fa754989ee031b6a93eb70be | |
parent | 9a99c7cef533e985e67af5de0e65a39f452b7db9 (diff) | |
download | rails-a3ddd5f1572f6ebf95f4c0a789413ee1b2ecbab5.tar.gz rails-a3ddd5f1572f6ebf95f4c0a789413ee1b2ecbab5.tar.bz2 rails-a3ddd5f1572f6ebf95f4c0a789413ee1b2ecbab5.zip |
Use correct timezone when parsing date in json
Fixes https://github.com/rails/rails/issues/22171
Time specified in ISO 8601 format without `Z` should be considered as local
time, yet until now it was treated as UTC.
This commit fixes problem by parsing time using timezone specified in
application config.
The downside of this solution is performance hit (`Time.zone.parse` is ~ 1.6x
slower than `Time.parse`), so maybe there's a better solution.
-rw-r--r-- | activesupport/CHANGELOG.md | 5 | ||||
-rw-r--r-- | activesupport/lib/active_support/json/decoding.rb | 11 | ||||
-rw-r--r-- | activesupport/test/json/decoding_test.rb | 16 |
3 files changed, 25 insertions, 7 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 21c79949ca..a383a05941 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fix parsing JSON time in `YYYY-MM-DD hh:mm:ss` (without `Z`). + Before such time was considered in UTC timezone, now, to comply with standard, it uses local timezone. + + *Grzegorz Witek* + * Match `HashWithIndifferentAccess#default`'s behaviour with `Hash#default`. *David Cornu* diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index 2932954f03..64e4b0e7a9 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -8,7 +8,8 @@ module ActiveSupport module JSON # matches YAML-formatted dates - DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/ + DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/ + DATETIME_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/ class << self # Parses a JSON string (JavaScript Object Notation) into a hash. @@ -48,7 +49,13 @@ module ActiveSupport nil when DATE_REGEX begin - DateTime.parse(data) + Date.parse(data) + rescue ArgumentError + data + end + when DATETIME_REGEX + begin + Time.zone.parse(data) rescue ArgumentError data end diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index f2fc456f4b..887ef1681d 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -1,8 +1,11 @@ require 'abstract_unit' require 'active_support/json' require 'active_support/time' +require 'time_zone_test_helpers' class TestJSONDecoding < ActiveSupport::TestCase + include TimeZoneTestHelpers + class Foo def self.json_create(object) "Foo" @@ -24,10 +27,11 @@ class TestJSONDecoding < ActiveSupport::TestCase %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)], %(["2007-01-01 01:12:34 Z", "2007-01-01 01:12:35 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34), Time.utc(2007, 1, 1, 1, 12, 35)], # no time zone - %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, + %({"a": "2007-01-01 01:12:34"}) => {'a' => Time.new(2007, 1, 1, 1, 12, 34, "-05:00")}, # invalid date %({"a": "1089-10-40"}) => {'a' => "1089-10-40"}, # xmlschema date notation + %({"a": "2009-08-10T19:01:02"}) => {'a' => Time.new(2009, 8, 10, 19, 1, 2, "-04:00")}, %({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)}, %({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)}, %({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)}, @@ -72,10 +76,12 @@ class TestJSONDecoding < ActiveSupport::TestCase TESTS.each_with_index do |(json, expected), index| test "json decodes #{index}" do - with_parse_json_times(true) do - silence_warnings do - assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ - failed for #{json}" + with_tz_default 'Eastern Time (US & Canada)' do + with_parse_json_times(true) do + silence_warnings do + assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ + failed for #{json}" + end end end end |