我正在将DateTime转换为OADate。我期望将OADate转换回时获得完全相同的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
提示来自:634202170964319073
来自b的提示:634202170964310000
The OADate double:40437.290467951389
这是什么原因? DateTime的分辨率显然足够好。
ToOADate调用的静态方法将滴答声清楚地除以10000,然后将结果存储在很长的时间中,从而删除了任何不到毫秒的信息
有人知道在哪里可以找到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
的作者将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)); // <-- HERE, remove this comment
}
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
现在,如果使用上述静态ourOADate
方法将DateTime
转换回FromOADatePrecise
,则会得到
[
2010-09-16T06:58:16.4319072
(以"O"
格式编写]
与原始图像相比,我们看到在这种情况下精度损失为0.1 µs。我们希望精度损失在±0.4 µs之内,因为此间隔的长度为0.8 µs,与前面提到的0.6286 µs相仿。使用如果采用另一种方法,则以
double
开头,它表示OA日期不太接近1900年,而first
FromOADatePrecise
,而then
ToOADatePrecise
,那么我们回到double
,并且由于中间DateTime
的精度优于OA日期,因此在这种情况下,我们希望实现完美的往返。另一方面,如果您以相同的顺序使用BCL方法FromOADate
和ToOADate
,则很难实现良好的往返(除非我们以double
开头的格式非常特殊) 。