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

时间:2010-09-16 06:57:25

标签: c# .net datetime resolution ole-automation

我正在将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的分辨率显然足够好。

3 个答案:

答案 0 :(得分:10)

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

除非您的日期非常接近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μs

我们得出结论,在此区域 a DateTime比OA日期更精确(仅仅过了)6倍。

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

如果我们采取相反的方式,从代表OA日期的double开始并不太接近1900年,首先使用FromOADatePrecise那么 ToOADatePrecise,然后我们回到double,因为中间DateTime的精度优于OA日期的精度,我们期望一个完美的圆 - 在这种情况下旅行。另一方面,如果您以相同的顺序使用BCL方法FromOADateToOADate,那么获得良好的往返是极不可能的(除非我们开始double有一个非常特殊的形式)。

答案 1 :(得分:3)

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);
    }

答案 2 :(得分:1)

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