.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.