我认为这是一个很好的问题。 (我才发现的。)
除非您使用非常接近 1900 年的日期进行操作,否则 DateTime 将具有比 OA 日期更高的精度。但是由于一些模糊的原因,DateTime 结构的作者只是 love 在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
任何DateTime 的精度为 0.1 µs。
在我们正在考虑的日期和时间附近,OA 日期的精度为:
Math.Pow(2.0, -37.0) 天,或大约 0.6286 µs
我们得出结论,在这个地区DateTime 比 OA 日期精确(刚好超过)六倍。
让我们使用我上面的扩展方法将ourDT 转换为double
double ourOADate = ourDT.ToOADatePrecise();
// .ToString("G") gives 40437.2904679619
// .ToString("R") gives 40437.290467961888
现在,如果您使用上面的静态FromOADatePrecise 方法将ourOADate 转换回DateTime,您会得到
2010-09-16T06:58:16.4319072(写成"O"格式)
与原始版本相比,我们看到在这种情况下精度损失为 0.1 µs。我们预计精度损失在 ±0.4 µs 以内,因为此间隔的长度为 0.8 µs,与前面提到的 0.6286 µs 相当。
如果我们采用另一种方式,从 double 开始,表示不太接近 1900 年的 OA 日期,首先使用FromOADatePrecise,然后然后 ToOADatePrecise,然后我们回到double,因为中间DateTime 的精度优于OA 日期,我们期望在这种情况下完美往返。另一方面,如果您以相同的顺序使用 BCL 方法 FromOADate 和 ToOADate,则极不可能获得良好的往返(除非我们开始使用的 double 具有非常特殊的形式) .