diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb index b50667c315..3cb4bf3c7e 100644 --- a/ext/psych/lib/psych/scalar_scanner.rb +++ b/ext/psych/lib/psych/scalar_scanner.rb @@ -63,7 +63,7 @@ module Psych elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/) require 'date' begin - class_loader.date.strptime(string, '%Y-%m-%d') + class_loader.date.strptime(string, '%F', Date::GREGORIAN) rescue ArgumentError string end diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb index cce5daf3bb..8614251ca9 100644 --- a/ext/psych/lib/psych/visitors/to_ruby.rb +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -80,7 +80,9 @@ module Psych when "!ruby/object:DateTime" class_loader.date_time require 'date' unless defined? DateTime - @ss.parse_time(o.value).to_datetime + t = @ss.parse_time(o.value) + DateTime.civil(*t.to_a[0, 6].reverse, Rational(t.utc_offset, 86400)) + + (t.subsec/86400) when '!ruby/encoding' ::Encoding.find o.value when "!ruby/object:Complex" diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb index 316a3a9496..31858798e4 100644 --- a/ext/psych/lib/psych/visitors/yaml_tree.rb +++ b/ext/psych/lib/psych/visitors/yaml_tree.rb @@ -192,12 +192,13 @@ module Psych register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY) end + def visit_Date o + register o, visit_Integer(o.gregorian) + end + def visit_DateTime o - formatted = if o.offset.zero? - o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze) - else - o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze) - end + t = o.italy + formatted = format_time t, t.offset.zero? tag = '!ruby/object:DateTime' register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY) end @@ -235,7 +236,6 @@ module Psych end alias :visit_TrueClass :visit_Integer alias :visit_FalseClass :visit_Integer - alias :visit_Date :visit_Integer def visit_Float o if o.nan? @@ -482,8 +482,8 @@ module Psych @emitter.end_mapping end - def format_time time - if time.utc? + def format_time time, utc = time.utc? + if utc time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") else time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") diff --git a/test/psych/test_date_time.rb b/test/psych/test_date_time.rb index 6f1e8b509e..3379bd24bf 100644 --- a/test/psych/test_date_time.rb +++ b/test/psych/test_date_time.rb @@ -44,6 +44,26 @@ module Psych assert_match(/12:00:00-05:00/, cycled.last.to_s) end + def test_julian_date + d = Date.new(1582, 10, 4, Date::GREGORIAN) + assert_cycle d + end + + def test_proleptic_gregorian_date + d = Date.new(1582, 10, 14, Date::GREGORIAN) + assert_cycle d + end + + def test_julian_datetime + dt = DateTime.new(1582, 10, 4, 23, 58, 59, 0, Date::GREGORIAN) + assert_cycle dt + end + + def test_proleptic_gregorian_datetime + dt = DateTime.new(1582, 10, 14, 23, 58, 59, 0, Date::GREGORIAN) + assert_cycle dt + end + def test_invalid_date assert_cycle "2013-10-31T10:40:07-000000000000033" end