Skip to content

Commit

Permalink
Improve ActiveSupport::TimeWithZone conversion to YAML
Browse files Browse the repository at this point in the history
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 rails#9183.
  • Loading branch information
pixeltrix committed Apr 22, 2015
1 parent 5302d24 commit 3aa26cf
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 8 deletions.
6 changes: 6 additions & 0 deletions activesupport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
13 changes: 7 additions & 6 deletions activesupport/lib/active_support/time_with_zone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,13 @@ def as_json(options = nil)
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
Expand Down
9 changes: 9 additions & 0 deletions activesupport/lib/active_support/values/time_zone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,15 @@ def periods_for_local(time) #:nodoc:
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?
Expand Down
47 changes: 45 additions & 2 deletions activesupport/test/core_ext/time_with_zone_test.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -123,11 +124,53 @@ def test_xmlschema_with_nil_fractional_seconds
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
Expand Down
9 changes: 9 additions & 0 deletions activesupport/test/time_zone_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -487,4 +487,13 @@ def test_us_zones
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

0 comments on commit 3aa26cf

Please sign in to comment.