.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
мы начали с очень специальной формы).