.NET DateTime, разное разрешение при конвертации в 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

Клещи от: 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 году, 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 мкс

Мы заключаем, что в этом регионе 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 мкс. Мы ожидаем, что потеря точности будет в пределах ±0,4 мкс, поскольку этот интервал имеет длину 0,8 мкс, что сравнимо с упомянутыми ранее 0,6286 мкс.

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

Вероятно, что-то связано с точностью двойного, а не с DateTime.

Другие вопросы по тегам