SQL Server中不期望的DateTime舍入

Odr*_*ade 11 sql-server datetime rounding

我碰到了一些奇怪的东西.DateTime当我将它们保存到datetime列时,SQL Server似乎不恰当地舍入了一些值.我怀疑我错过了什么,但我无法发现它.我正在使用.NET 4.0对SQL Server 2008运行此测试.以下内容应说明问题:

我在SQL Server中创建了一个名为Timestamps的表.它有两列:

id - bigint,Identity,PK
timestamp - datetime

我还创建了一个简单的测试,它执行以下操作:

  1. 获取当前时间,将值截断为毫秒精度
  2. 保存截断的时间 Timestamps
  3. 从DB中检索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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我希望截断的值等于从DB返回的值,但情况并非总是如此.这是一些示例输出:

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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

是什么赋予了?这真是不合适的四舍五入,还是我在这里做出错误的假设?

Mik*_* M. 17

日期时间仅精确到3毫秒.因此它将四舍五入到最接近3ms的倍数.要解决这个问题,请查看datetime2.请注意,这仅适用于SQL2008 +

编辑:它不仅仅是3毫秒.它的四舍五入为.000,.003或.007秒的增量

  • 实际上,它以两个 4 字节整数存储日期时间,第一个表示日期,第二个 4 字节整数表示自午夜以来的时钟滴答数。(每个大约 3.33 毫秒) (2认同)