.NET DateTime,与OADate进行转换时的分辨率是否不同?

我正在将DateTime转换为OADate。 我希望在将OADa​​te转换回时获得完全相同的DateTime,但现在它只有毫秒级的分辨率,因此不同。

var a = DateTime.UtcNow; double oadate = a.ToOADate(); var b = DateTime.FromOADate(oadate); int compare = DateTime.Compare(a, b); //Compare is not 0; the date times are not the same 

来自a:634202170964319073

来自b的筹码:634202170964310000

OADate双倍:40437.290467951389

这是什么原因? DateTime的分辨率显然足够好。

ToOADate调用的静态方法清楚地将ticks除以10000,然后将结果存储为long,从而删除任何亚毫秒信息

有谁知道在哪里可以找到OADate格式的规格?

  private static double TicksToOADate(long value) { if (value == 0L) { return 0.0; } if (value < 0xc92a69c000L) { value += 0x85103c0cb83c000L; } if (value < 0x6efdddaec64000L) { throw new OverflowException(Environment.GetResourceString("Arg_OleAutDateInvalid")); } long num = (value - 0x85103c0cb83c000L) / 0x2710L; if (num < 0L) { long num2 = num % 0x5265c00L; if (num2 != 0L) { num -= (0x5265c00L + num2) * 2L; } } return (((double)num) / 86400000.0); } 

我认为这是一个很好的问题。 (我刚发现它。)

除非您的日期非常接近1900年,否则DateTime精确度将高于 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 

任何DateTime的精度为0.1μs。

在我们考虑的日期和时间附近,OA日期的精确度是:

Math.Pow(2.0, -37.0)天,或大约0.6286

我们得出结论, 在这个区域中DateTime比OA日期更精确(通过)6倍。

让我们使用上面的扩展方法将我的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相当。

如果我们采用另一种方式,从表示OA日期不太接近1900年的double开始, 首先使用FromOADatePrecise然后使用 ToOADatePrecise ,那么我们将返回到double ,因为中间DateTime的精度更高对于OA日期,我们期望在这种情况下完美的往返。 另一方面,如果您以相同的顺序使用BCL方法FromOADateToOADate ,则很难获得良好的往返(除非我们开始的double具有非常特殊的forms)。

可能与double的精度有关,而不是DateTime。