【发布时间】:2011-05-17 11:55:46
【问题描述】:
我遇到了一些看起来很奇怪的事情。当我将某些DateTime 值保存到datetime 列时,SQL Server 似乎不恰当地舍入它们。我怀疑我错过了什么,但我无法发现它。我正在使用 .NET 4.0 针对 SQL Server 2008 运行此测试。下面应该说明这个问题:
我在 SQL Server 中创建了一个名为 Timestamps 的表。它有两列:
id - bigint、Identity、PK
时间戳 - 日期时间
我还创建了一个简单的测试,它执行以下操作:
- 获取当前时间,将值截断到毫秒精度
- 将截断的时间保存到
Timestamps - 从数据库中检索到 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