DATEADD 和 DATEPART 以毫秒为单位产生奇怪的结果

Sas*_*M78 5 sql-server datatypes datetime sql-server-2016

我有一个包含 unix 时间日期和一个单独的毫秒字段的表。我现在尝试从两个字段中创建一个日期以供以后计算(例如过滤时间范围)。将毫秒添加到通过...创建的日期后

 dateadd(S, [timestamp_s], '1970-01-01')
Run Code Online (Sandbox Code Playgroud)

通过添加另一个DATEADD...

dateadd(MS, [timestamp_ms], dateadd(S, [timestamp_s], '1970-01-01')) eventdate
Run Code Online (Sandbox Code Playgroud)

...然后输出日期毫秒有时关闭一毫秒。出于好奇,我然后尝试提取毫秒,看看这给出了什么,然后又减少了 1 毫秒。

在此处输入图片说明

我认为这与内部浮点精度有关,但我在数据中看不到任何规则。有时每个操作都会减少 1 毫秒,有时第一个会减 1,但 DATEPART 然后会再次加 1,等等。

由于这可能会导致某些用户感到沮丧,因此我想了解这种行为并在理想情况下找到问题的解决方案。提前致谢。

Jos*_*ell 12

这是由于数据类型准确性的奇怪限制1datetime如文档所示

精度 | 舍入到 .000、.003 或 0.007 秒的增量

解决方案是使用datetime2,它提供了更好的准确性,正如您在此dbfiddle 演示所见

dbfiddle 结果的屏幕截图显示了使用 datetime2 时正确的毫秒数

的返回类型DATEADD是动态的,取决于您发送给它的内容。所以重要的是确保你正在传递datetime2到你添加毫秒的步骤。


1 Randolph West有一个关于 SQL Server 数据类型如何存储的精彩博客系列,包括日期和时间(SQL Server 如何存储数据类型:日期和时间)。该帖子有来自数据平台 MVP Jeff Moden 的有用评论:

DATETIME 的时间部分实际上是自午夜以来经过的 1/300 秒数的整数计数。这转化为 3.3 毫秒的分辨率,但对于数据存储方式而言,这种分辨率水平是不可能的,因此 0.0 和 3.3 毫秒向下舍入为 0 毫秒,而 3 毫秒和 6.6 毫秒向上舍入为 7 毫秒。