J'ai rencontré quelque chose qui semble étrange. SQL Server semble arrondir certaines valeurs DateTime
de manière inappropriée lorsque je les enregistre dans des colonnes datetime
. Je soupçonne qu'il me manque quelque chose, mais je ne le vois pas. J'exécute ce test sur SQL Server 2008 en utilisant .NET 4.0. Les éléments suivants doivent illustrer le problème:Arrondi indésirable de DateTime dans SQL Server
J'ai créé une table dans SQL Server appelée Timestamps. Il dispose de deux colonnes:
id - bigint, Identité, PK
timestamp - datetime
J'ai aussi créé un test simple qui effectue les opérations suivantes:
- Obtient l'heure actuelle , tronquer la valeur à la milliseconde précision
- sauvé le temps tronqué à
Timestamps
Récupération de la valeur datetime dans la base de données et comparaison avec l'objet DateTime d'origine (tronqué).
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();
}
}
}
Bien que j'attends la valeur tronquée soit équivalente à la valeur renvoyée en retrait de la DB, ce n'est pas toujours le cas. Voici quelques exemple de sortie:
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()
ressemble à ceci:
public static DateTime TruncateToMilliseconds(this DateTime t)
{
return new DateTime(t.Year, t.Month, t.Day, t.Hour, t.Minute, t.Second, t.Millisecond);
}
Qu'est-ce qui se passe? Est-ce vraiment un arrondissement inapproprié, ou est-ce que je fais une supposition erronée ici?
En fait, il stocke un datetime dans deux entiers de 4 octets, le premier représentant la date, et le second entier de 4 octets représentant le nombre de ticks d'horloge depuis minuit. (environ 3,33 millisecondes chacun) –
Correct. Finit par être .003, .007 ou .000 –
Merci! J'ai juste supposé que datetime était précis à 1ms, puisqu'il a une précision de 1ms. – Odrade