I ran into something that seems odd. SQL Server appears to be rounding some DateTime
values inappropriately when I save them to datetime
columns. I suspect I'm missing something, but I can't spot it. I'm running this test against SQL Server 2008 using .NET 4.0. The following should illustrate the issue:
I have created a table in in SQL Server called Timestamps. It has two columns:
id - bigint, Identity, PK
timestamp - datetime
I also created a simple test that does the following:
Timestamps
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();
}
}
}
Although I expect the truncated value to be equivalent to the value returned back from the DB, that is not always the case. Here's some sample output:
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()
looks like this:
public static DateTime TruncateToMilliseconds(this DateTime t)
{
return new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second, t.Millisecond);
}
What gives? Is this really inappropriate rounding, or am I making a mistaken assumption here?
Rounding or truncating timestamps are especially useful when you're grouping by time. If you are rounding by year, you can use the corresponding function: select year(getdate()) as 'Year'; Be careful if you are grouping by months or smaller timestamp fragments (weeks, days, hours, minutes).
SQL Server ROUND() Function The ROUND() function rounds a number to a specified number of decimal places. Tip: Also look at the FLOOR() and CEILING() functions.
Datetime is only accurate to 3ms. Therefore it'll round to the nearest multiple of 3ms. To overcome this, look at the datetime2. Note that this is for SQL2008+ only
EDIT: it's not quite only to 3ms. It's rounded to increments of of .000, .003, or .007 seconds
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With