Насколько точен DateTime.AddDays? - PullRequest
2 голосов
/ 20 апреля 2009

Поскольку DateTime.AddDays () принимает параметр double, я обеспокоен тем, что при добавлении дней могут возникнуть некоторые ошибки округления. Например, допустим, у меня есть следующий цикл:

DateTime Now = DateTime.Today;
for (int i = 0; i < 365; ++i)
{
    Now = Now.AddDays(1);
    // do something
}

Я обеспокоен тем, что Сейчас может начать уходить с полуночи. Я всегда испытываю желание сделать что-то подобное, что может быть немного медленнее, но облегчает мою паранойю:

for (int i = 0; i < 365; ++i)
{
    Now = Now.AddDays(1.01).Date;
    // do something
}

Ответы [ 5 ]

11 голосов
/ 20 апреля 2009

Поскольку DateTime хранит внутреннюю дату как 64-битное целое число, где один тик представляет 100 наносекунд, риск ошибки отсутствует. Один день имеет 864 000 000 000 тиков, а Double имеет точность не менее 15 цифр. Таким образом, каждая ошибка исчезает при округлении до тиков, потому что Double имеет более высокое разрешение, чем один тик, если 1.0 равно одному дню.

Это не будет верно для AddYears(), потому что Double не имеет достаточной точности для представления одного тика, если 1.0 равен одному году. Но если вы посмотрите на класс DateTime, вы увидите, что проект учитывает этот факт - AddMonths() и AddYears() имеют как целочисленные, так и не плавающие аргументы.

Для проверки просто выполните следующий код.

DateTime now = DateTime.Now;

// Displays 864000000000 
Console.WriteLine(now.AddDays(1.0).Ticks - now.Ticks);
2 голосов
/ 20 апреля 2009

В целом, я думаю, что вы правильно беспокоитесь о округлении с двойными, поскольку не все действительные числа абсолютно выразимы с двойным - например, если вы добавляете 1/3 дня три раза, вы можете этого не делать в итоге ровно на один день вперед. Однако в этом случае 1 - это число, которое абсолютно выразимо, и, поскольку вы просто умножаете его на другое число, которое также абсолютно выразимо в двойном значении (число тиков в день), у вас должно быть все в порядке. Второй образец, вероятно, излишний.

Пример:

DateTime now = DateTime.Today;
for (int i = 0; i < 7; ++i )
{
    for (int j = 0; j < 7; ++j )
    {
         now = now.AddDays( 1 / 7.0 );
    }
}
Console.WriteLine( DateTime.Today);
Console.WriteLine( now );

Результаты (20.04.2009)

4/20/2009 12:00:00 AM
4/26/2009 11:59:59 PM
1 голос
/ 20 апреля 2009

Количество дней умножается на целое число (шкалу), а затем добавляется к числу тиков, сохраненному в DateTime. Когда вы передаете целое число, вы в конечном итоге добавляете целое число тиков.

С другой стороны, я не знаю, что .NET делает с високосными секундами ... Я подозреваю, что она использует довольно простую модель, которая не беспокоит их, оставляя ваш код в порядке.

Не забывайте, что добавление часовых поясов добавляет дополнительную сложность - добавление дня локально может добавить больше или меньше дня с точки зрения UTC, и наоборот.

0 голосов
/ 20 апреля 2009

Как и в вашем примере, я добавил 1 день в переменную DateTime 100 000 раз и по-прежнему заканчивал дату со значением полуночи. Похоже, что нет причин для беспокойства.

Я уверен, что они округляются до временных отметок, что устраняет любые проблемы с дрифтингом.

0 голосов
/ 20 апреля 2009

Что вы подразумеваете под уходом от полуночи?

При запуске первый код имеет последнюю дату, имеющую 20.04.2010, 12:00:00.
Я думаю, это то, что вы ожидаете. Не так ли?

...