Me encontré con algo que parece extraño. SQL Server parece estar redondeando algunos valores DateTime
de forma inapropiada cuando los guardo en columnas datetime
. Sospecho que me estoy perdiendo algo, pero no puedo encontrarlo. Estoy ejecutando esta prueba contra SQL Server 2008 usando .NET 4.0. Lo siguiente debe ilustrar el problema:Redondeo no deseado de DateTime en SQL Server
He creado una tabla en SQL Server llamada Timestamps. Tiene dos columnas:
Identificación - bigint, Identidad, PK
marca de tiempo - fecha y hora
También creé una prueba simple que hace lo siguiente:
- Obtiene la hora actual , truncando el valor a una precisión de milisegundos
- Se guardó el tiempo truncado en
Timestamps
- Recuperó el valor datetime` de la base de datos y lo comparó con el objeto DateTime original (truncado).
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();
}
}
}
Aunque espero que el valor truncado sea equivalente al valor devuelto de nuevo a partir de la base de datos, que no siempre es el caso. Aquí está un ejemplo de salida:
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()
se parece a esto:
public static DateTime TruncateToMilliseconds(this DateTime t)
{
return new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second, t.Millisecond);
}
Lo que da? ¿Es esto realmente inadecuado redondear, o estoy haciendo una suposición errónea aquí?
En realidad, almacena una fecha y hora en dos enteros de 4 bytes, el primero que representa la fecha y el segundo número entero de 4 bytes que representa la cantidad de marcas de reloj desde la medianoche. (aproximadamente 3.33 milésegundos cada uno) –
Correcto. Termina siendo .003, .007 o .000 –
¡Gracias! Simplemente asumí que datetime era preciso a 1 ms, ya que tiene una precisión de 1 ms. – Odrade