【发布时间】:2020-11-09 14:25:51
【问题描述】:
这个问题不是关于将 DateTime 序列化为 double 和 back 是否明智的做法,而是关于当这是您必须做的事情时该怎么做。
表面上的解决方案是使用DateTime.ToOADate(),按照Convert DateTime to Double,但这会严重损失精度,例如
let now = DateTime.UtcNow in DateTime.FromOADate(now.ToOADate()).Ticks - now.Ticks
导致类似
val it : int64 = -7307L,这几乎是一毫秒。
在这方面,更粗略的方法(只是在long 和double(在F# 中称为float)之间进行转换实际上要好一些:
let now = DateTime.UtcNow in DateTime(int64(float(now.Ticks))).Ticks - now.Ticks
产生类似val it : int64 = -42L 的结果——更好,但仍然不准确。例如,C#: Double to long conversion 中讨论了精度损失的原因。
所以问题是:有没有办法将DateTime 往返于double 并返回,而不会损失精度?
更新:接受的答案很清楚地解释了“它实际上是如何工作的”,但事实证明System.BitConverter.Int64BitsToDouble() 和System.BitConverter.DoubleToInt64Bits() 或多或少地做了这些,尽管显然受限于longdouble转换,并且仅在 little-endian 机器上。实际代码见https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs,db20ea77a561c0ac。
【问题讨论】:
-
为什么要坚持使用double?最直接的往返是通过
Ticks,也就是long,通过对应的构造函数就可以恢复。 -
我在第一段中解决了这个问题。我意识到序列化 long 显然是正确的做法,但在我的情况下,用于存储 DateTime 的“API”恰好是通过存储/读取双精度 - 因此产生了这个问题。
标签: c# .net datetime serialization f#