SQL Server中不期望的DateTime舍入

时间:2010-11-29 20:13:13

标签: sql-server datetime rounding

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

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

id - bigint,Identity,PK
时间戳 - 日期时间

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

  1. 获取当前时间,将值截断为毫秒精度
  2. 将截断时间保存为Timestamps
  3. 从数据库中检索datetime`值,并将其与原始(截断的)DateTime对象进行比较。
  4. 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();
            }
        }
    }
    

    虽然我希望截断的值等于从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
    

    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 个答案:

答案 0 :(得分:15)

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

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