Нежелательное округление DateTime в SQL Server - PullRequest
10 голосов
/ 29 ноября 2010

Я столкнулся с чем-то странным.Похоже, что SQL Server неправильно округляет некоторые значения DateTime, когда я сохраняю их в столбцы datetime.Я подозреваю, что что-то упустил, но не могу это определить.Я запускаю этот тест на SQL Server 2008 с использованием .NET 4.0.Следующее должно иллюстрировать проблему:

Я создал таблицу в SQL Server с именем Timestamps.Он имеет два столбца:

id - bigint, Identity, PK
метка времени - дата-время

Я также создал простой тест, который выполняетследующее:

  1. Получает текущее время, обрезая значение с точностью до миллисекунды
  2. Сохраняет усеченное время до Timestamps
  3. Получает значение datetime` изБД и сравнил его с исходным (усеченным) объектом DateTime.
public static void RoundTest()
{
    DateTime preTruncation = DateTime.UtcNow;
    DateTime truncated = preTruncation.TruncateToMilliseconds();

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["test"].ConnectionString))
    {
        conn.Open();
        SqlCommand cmd = new SqlCommand(@"INSERT INTO Timestamps(timestamp) 
                                            VALUES(@savedTime); 
                                            SELECT SCOPE_IDENTITY() AS id");
        cmd.Parameters.Add(new SqlParameter("savedTime", truncated));
        cmd.Connection = conn;
        var id = cmd.ExecuteScalar();

        SqlCommand get = new SqlCommand(@"SELECT timestamp FROM Timestamps 
                                            WHERE id = @id");

        get.Parameters.Add(new SqlParameter("id", id));
        get.Connection = conn;
        DateTime retrieved = (DateTime)get.ExecuteScalar();

        if (retrieved != truncated)
        {
            Console.WriteLine("original: " + preTruncation.TimeOfDay);
            Console.WriteLine("truncated: " + truncated.TimeOfDay);
            Console.WriteLine("retrieved: " + retrieved.TimeOfDay);
            Console.WriteLine();
        }
    }
}

Хотя я ожидаю, что усеченное значение будет эквивалентно значению, возвращенному из БД, но это не всегда так.Вот пример вывода:

original: 19:59:13.4049965
truncated: 19:59:13.4040000
retrieved: 19:59:13.4030000

original: 19:59:14.4989965
truncated: 19:59:14.4980000
retrieved: 19:59:14.4970000

original: 19:59:15.4749965
truncated: 19:59:15.4740000
retrieved: 19:59:15.4730000

original: 19:59:30.1549965
truncated: 19:59:30.1540000
retrieved: 19:59:30.1530000

TruncateToMilliseconds() выглядит так:

public static DateTime TruncateToMilliseconds(this DateTime t)
{
    return new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second, t.Millisecond);
}

Что дает?Это действительно неуместное округление, или я делаю ошибочное предположение здесь?

1 Ответ

15 голосов
/ 29 ноября 2010

Дата и время точны только до 3 мс.Поэтому оно округляется до ближайшего кратного 3 мс.Чтобы преодолеть это, посмотрите на datetime2 .Обратите внимание, что это только для SQL2008 +

EDIT: не только до 3 мс.Он округляется с шагом .000, .003 или .007 секунд

...