我认为这是一个很好的问题。(我刚刚发现它。)
除非您使用非常接近 1900 年的日期进行操作,否则 aDateTime
将具有比 OA 日期更高的精度。但是由于一些模糊的原因,DateTime
结构的作者只是喜欢DateTime
在和其他东西之间转换时截断到最接近的整毫秒。不用说,这样做会在没有充分理由的情况下丢掉很多精度。
这是一个解决方法:
static readonly DateTime oaEpoch = new DateTime(1899, 12, 30);
public static DateTime FromOADatePrecise(double d)
{
if (!(d >= 0))
throw new ArgumentOutOfRangeException(); // NaN or negative d not supported
return oaEpoch + TimeSpan.FromTicks(Convert.ToInt64(d * TimeSpan.TicksPerDay));
}
public static double ToOADatePrecise(this DateTime dt)
{
if (dt < oaEpoch)
throw new ArgumentOutOfRangeException();
return Convert.ToDouble((dt - oaEpoch).Ticks) / TimeSpan.TicksPerDay;
}
现在,让我们考虑(根据您的问题)由DateTime
下式给出:
var ourDT = new DateTime(634202170964319073);
// .ToSting("O") gives 2010-09-16T06:58:16.4319073
any 的精度DateTime
为 0.1 µs。
在我们考虑的日期和时间附近,OA 日期的精度为:
Math.Pow(2.0, -37.0)
天,或大约0.6286
µs
我们得出的结论是,在该区域中, aDateTime
比 OA 日期更精确(刚好超过)六倍。
让我们转换ourDT
为double
使用我上面的扩展方法
double ourOADate = ourDT.ToOADatePrecise();
// .ToString("G") gives 40437.2904679619
// .ToString("R") gives 40437.290467961888
现在,如果您使用上面的静态方法转换ourOADate
回 a ,您会得到DateTime
FromOADatePrecise
2010-09-16T06:58:16.4319072
(用"O"
格式写)
与原始数据相比,我们看到在这种情况下精度损失为 0.1 µs。我们预计精度损失在 ±0.4 µs 内,因为该间隔的长度为 0.8 µs,与前面提到的 0.6286 µs 相当。
如果我们换一种方式,从double
表示 OA 日期不太接近 1900 年的a 开始,先使用FromOADatePrecise
,然后 ToOADatePrecise
使用 ,然后回到 a double
,因为中间DateTime
值的精度优于 OA日期,我们期望在这种情况下完美的往返。另一方面,如果您使用 BCL 方法FromOADate
并ToOADate
以相同的顺序,则极不可能获得良好的往返(除非double
我们开始使用的形式非常特殊)。