【问题标题】:Undesired rounding of DateTime in SQL ServerSQL Server 中不希望的 DateTime 舍入
【发布时间】:2011-05-17 11:55:46
【问题描述】:

我遇到了一些看起来很奇怪的事情。当我将某些DateTime 值保存到datetime 列时,SQL Server 似乎不恰当地舍入它们。我怀疑我错过了什么,但我无法发现它。我正在使用 .NET 4.0 针对 SQL Server 2008 运行此测试。下面应该说明这个问题:

我在 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);
}

什么给了?这真的是不适当的舍入,还是我在这里做出了错误的假设?

【问题讨论】:

  • 显然 SQL 标准是四舍五入(不是截断)......这很可怕,因为它会导致将来出现意外的日期时间。即使同一台服务器随后查询“将来不是的所有内容”,也可能会排除其刚刚确定和刚刚插入的日期时间(根据定义,我们不会考虑在未来)。

标签: sql-server datetime rounding


【解决方案1】:

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

编辑:不仅仅是 3 毫秒。它以 0.000、0.003 或 0.007 秒的增量四舍五入

【讨论】:

  • 实际上,它将日期时间存储在两个 4 字节整数中,第一个表示日期,第二个 4 字节整数表示从午夜开始的时钟滴答数。 (每个大约 3.33 毫秒)
  • 正确。最终成为 .003、.007 或 .000
  • 谢谢!我只是假设日期时间精确到 1 毫秒,因为它的精度为 1 毫秒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多