.NET DateTime, различное разрешение при преобразовании в OADate и из OADate?

Я конвертирую DateTime в OADate. Я ожидал получить точно такое же DateTime при преобразовании OADate обратно, но теперь он имеет только миллисекундное разрешение и, следовательно, отличается.

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 ответов


статический метод, вызываемый 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 году, a 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 МКС.

рядом с датой и временем, которые мы рассматриваем, точность даты OA:

Math.Pow(2.0, -37.0) дней, или около 0.6286 µs

Мы заключаем, что в регионе a DateTime более точно, чем дата OA (чуть больше) фактор шесть.

превратим ourDT to double используя мой метод расширения выше

double ourOADate = ourDT.ToOADatePrecise();
// .ToString("G") gives 40437.2904679619
// .ToString("R") gives 40437.290467961888

теперь, если вы конвертируете ourOADate обратно в DateTime используя статический!--15--> метод выше, вы получаете

2010-09-16T06:58:16.4319072 (написано с )

сравнивая с оригиналом, мы видим, что потеря точности в данном случае 0.1 МКС. Мы ожидаем, что потеря точности будет в пределах ±0,4 МКС, так как это интервал имеет длину 0,8 МКС, что сопоставимо с 0,6286 МКС, упомянутыми ранее.

если мы пойдем в другую сторону, начиная с double представление даты OA не слишком близко к 1900 году, и первый использовать FromOADatePrecise и затем ToOADatePrecise, затем мы вернемся к double, и потому что точность промежуточного DateTime превосходит дату OA, мы ожидаем идеального туда и обратно в этом случае. Если, с другой стороны, вы используете BCL методы FromOADate и ToOADate в том же порядке крайне маловероятно получить хорошую поездку туда и обратно (если только double мы начали с очень специальной формы).


вероятно, имеет какое-то отношение к точности double, а не DateTime.