diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 21c79949cad24655722816a2ea1c4c8dfb47d999..a383a05941a482051142b8613bf38879e425ab87 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 2932954f03c73ef251ece161a5351158a6e31e1a..64e4b0e7a9b479868fbb8b2936470db52d00c318 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 @@ def convert_dates_from(data) 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 f2fc456f4b9e16129a4cd0c0502f2050464907fb..887ef1681df7d9630b12894ccfefcb7f22b900b3 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 @@ def self.json_create(object) %(["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 @@ def self.json_create(object) 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