Improve ActiveSupport::TimeWithZone conversion to YAML

Previously when converting AS::TimeWithZone to YAML it would be output
as a UTC timestamp. Whilst this preserves the time information accurately
it loses the timezone information. This commit changes that so that it is
saved along with the time information. It also provides nicer encoding of
AS::TimeZone instances themselves which previously embedded all of the
data from the TZInfo records.

Fixes #9183.
This commit is contained in:
Andrew White 2014-10-20 09:12:35 +01:00
parent 5302d244eb
commit 3aa26cfb19
5 changed files with 76 additions and 8 deletions

View File

@ -1,3 +1,9 @@
* Encoding ActiveSupport::TimeWithZone to YAML now preserves the timezone information.
Fixes #9183.
*Andrew White*
* Added `ActiveSupport::TimeZone#strptime` to allow parsing times as if
from a given timezone.

View File

@ -169,12 +169,13 @@ module ActiveSupport
end
end
def encode_with(coder)
if coder.respond_to?(:represent_object)
coder.represent_object(nil, utc)
else
coder.represent_scalar(nil, utc.strftime("%Y-%m-%d %H:%M:%S.%9NZ"))
end
def init_with(coder) #:nodoc:
initialize(coder['utc'], coder['zone'], coder['time'])
end
def encode_with(coder) #:nodoc:
coder.tag = '!ruby/object:ActiveSupport::TimeWithZone'
coder.map = { 'utc' => utc, 'zone' => time_zone, 'time' => time }
end
# Returns a string of the object's date and time in the format used by

View File

@ -428,6 +428,15 @@ module ActiveSupport
tzinfo.periods_for_local(time)
end
def init_with(coder) #:nodoc:
initialize(coder['name'])
end
def encode_with(coder) #:nodoc:
coder.tag ="!ruby/object:#{self.class}"
coder.map = { 'name' => tzinfo.name }
end
private
def parts_to_time(parts, now)
return if parts.empty?

View File

@ -1,6 +1,7 @@
require 'abstract_unit'
require 'active_support/time'
require 'time_zone_test_helpers'
require 'active_support/core_ext/string/strip'
class TimeWithZoneTest < ActiveSupport::TestCase
include TimeZoneTestHelpers
@ -123,11 +124,53 @@ class TimeWithZoneTest < ActiveSupport::TestCase
end
def test_to_yaml
assert_match(/^--- 2000-01-01 00:00:00(\.0+)?\s*Z\n/, @twz.to_yaml)
yaml = <<-EOF.strip_heredoc
--- !ruby/object:ActiveSupport::TimeWithZone
utc: 2000-01-01 00:00:00.000000000 Z
zone: !ruby/object:ActiveSupport::TimeZone
name: America/New_York
time: 1999-12-31 19:00:00.000000000 Z
EOF
assert_equal(yaml, @twz.to_yaml)
end
def test_ruby_to_yaml
assert_match(/---\s*\n:twz: 2000-01-01 00:00:00(\.0+)?\s*Z\n/, {:twz => @twz}.to_yaml)
yaml = <<-EOF.strip_heredoc
---
twz: !ruby/object:ActiveSupport::TimeWithZone
utc: 2000-01-01 00:00:00.000000000 Z
zone: !ruby/object:ActiveSupport::TimeZone
name: America/New_York
time: 1999-12-31 19:00:00.000000000 Z
EOF
assert_equal(yaml, { 'twz' => @twz }.to_yaml)
end
def test_yaml_load
yaml = <<-EOF.strip_heredoc
--- !ruby/object:ActiveSupport::TimeWithZone
utc: 2000-01-01 00:00:00.000000000 Z
zone: !ruby/object:ActiveSupport::TimeZone
name: America/New_York
time: 1999-12-31 19:00:00.000000000 Z
EOF
assert_equal(@twz, YAML.load(yaml))
end
def test_ruby_yaml_load
yaml = <<-EOF.strip_heredoc
---
twz: !ruby/object:ActiveSupport::TimeWithZone
utc: 2000-01-01 00:00:00.000000000 Z
zone: !ruby/object:ActiveSupport::TimeZone
name: America/New_York
time: 1999-12-31 19:00:00.000000000 Z
EOF
assert_equal({ 'twz' => @twz }, YAML.load(yaml))
end
def test_httpdate

View File

@ -487,4 +487,13 @@ class TimeZoneTest < ActiveSupport::TestCase
assert ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Hawaii"])
assert !ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Kuala Lumpur"])
end
def test_to_yaml
assert_equal("--- !ruby/object:ActiveSupport::TimeZone\nname: Pacific/Honolulu\n", ActiveSupport::TimeZone["Hawaii"].to_yaml)
assert_equal("--- !ruby/object:ActiveSupport::TimeZone\nname: Europe/London\n", ActiveSupport::TimeZone["Europe/London"].to_yaml)
end
def test_yaml_load
assert_equal(ActiveSupport::TimeZone["Pacific/Honolulu"], YAML.load("--- !ruby/object:ActiveSupport::TimeZone\nname: Pacific/Honolulu\n"))
end
end