DateTime序列化和反序列化

我想将一个Ruby DateTime对象序列化为json。 不幸的是,我的方法并不是对称的:

require 'date'
date = DateTime.now
DateTime.parse(date.to_s) == date
 => false

我可以使用一些任意的strftime / parse字符串组合,但我相信必须有更好的方法。


不幸的是,接受的答案并不是一个好的解决方案。 像往常一样,编组/解组是一种工具,你应该只用作最后的手段,但在这种情况下,它可能会破坏你的应用程序。

OP特别提到将日期序列化为JSON。 根据RFC 7159:

JSON文本应以UTF-8,UTF-16或UTF-32编码。 默认编码是UTF-8,以UTF-8编码的JSON文本是可互操作的,因为它们将通过最大数量的实现成功读取; 有很多实现无法成功读取其他编码中的文本(如UTF-16和UTF-32)。

现在让我们看看我们从元帅那里得到什么:

marsh = Marshal.dump(DateTime.now)
# => "x04bU:rDateTime[vix00ix03xE0x7F%ix02sxC9ix04xF8zxF1"ixFExB0xB9ff2299161"
puts marsh.encoding
# -> #<Encoding:ASCII-8BIT>

marsh.encode(Encoding::UTF_8)
# -> Encoding::UndefinedConversionError: "xE0" from ASCII-8BIT to UTF-8

除了返回一个不可读的值之外, Marshal.dump为我们提供了一个无法转换为UTF-8的值。 这意味着将其放入(有效)JSON的唯一方法是以某种方式对其进行编码,例如base-64。

没有必要这样做。 已经有一种可以互操作的方式来表示日期和时间:ISO 8601.我不会回顾为什么它是JSON的最佳选择(一般而言),但这里的答案涵盖了它:“正确”的JSON日期格式。

从Ruby 1.9.3开始,DateTime类分别具有iso8601类和实例方法来解析和格式化ISO 8601日期。 后者采用参数来指定小数秒的精度(例如3毫秒):

require "date"

date = DateTime.now
str = date.iso8601(9)
puts str
# -> 2016-06-28T09:35:58.311527000-05:00

DateTime.iso8601(str) == date
# => true

请注意,如果您指定较小的精度,则这可能不起作用,因为例如58.311不等于58.311527 。 精度9 (纳秒)对我来说似乎是安全的,因为DateTime文档说:

分数的精度假定在最大纳秒。

但是,如果您正在与可能使用更高精度的系统进行互操作,则应考虑到这一点。

最后,如果您想让Ruby的JSON库自动使用iso8601进行序列化,请覆盖as_jsonto_json方法:

unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
  require 'json'
end
require 'date'

class DateTime
  def as_json(*)
    iso8601(9)
  end

  def to_json(*args)
    as_json.to_json(*args)
  end
end

puts DateTime.now.to_json
# -> "2016-06-28T09:35:58.311527000-05:00"

to_s方法和to_json方法(提供to_json require 'json' )都会忽略由DateTime对象date存储的纳秒。 好的Marshal提供:

require 'date'
date = DateTime.now
m_date = Marshal.dump(date)
p Marshal.load(m_date) == date # => true

这是因为date有次秒值,并且#to_s方法将在几秒钟内返回ISO时间格式,所以比较不成功。

1.9.3p327 :021 > date = DateTime.now
 => #<DateTime: 2012-11-28T07:32:40+09:00 ((2456259j,81160s,283019000n),+32400s,2299161j)> 
1.9.3p327 :022 > DateTime.parse(date.to_s)
 => #<DateTime: 2012-11-28T07:32:40+09:00 ((2456259j,81160s,0n),+32400s,2299161j)> 

所以他们实际上是不同的。

如果你不关心亚秒,只是忘记比较是否成功。

或者,您可以为1.9.3使用DateTime#marshal_loadDateTime#marshal_dump 。 (直到现在我还不知道这个..)

它的工作原理是:

date1 = DateTime.now
dump  = date1.marshal_dump
date2 = DateTime.new.marshal_load(dump)
date1 == date2 # => true
链接地址: http://www.djcxy.com/p/46669.html

上一篇: DateTime serialization and deserialization

下一篇: How to deal with [NSDate] and Firebase