【问题标题】:SQL datetime2 cannot hold datetimeSQL datetime2 不能保存日期时间
【发布时间】:2021-02-28 11:54:43
【问题描述】:

似乎datetime2 在某些情况下无法保存datetime 值的值。这是预期的吗?

注意最后两列。还是转换损坏了数据?

SELECT
    DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267),
    CONVERT(datetime, DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267)),
    CONVERT(datetime2, DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267)),
    CAST(DATETIMEFROMPARTS (2021, 2, 28, 10, 11, 12, 267) AS datetime2)

我并不真正需要这些转换,但我遇到了 Entity Framework 的问题,即生成 SQL 将我的 datetime 转换为 datetime2,导致将其加载到 C# DateTime 时会出现细微差异

【问题讨论】:

  • 什么意思,它不能保存datetime 的值? datetime 精确到 1/300 秒,datetime2 可以精确到 1/1000000 秒。它可以保存datetime 的每个值等等。
  • 是的,这正是我的预期,但我提供的 SQL 讲述了一个不同的故事。
  • 不,不是,@Stig。
  • 简短答案 - 阅读文档。
  • @SM我已经读过了。但是如果 datetime 使用基于无限小数 (1/300) 的精度,那么 datetime2 应该如何表示呢? (精度相同)

标签: sql-server datetime2


【解决方案1】:

您的误解是您认为datetime 精确到1/1000 秒;它是不是。 .267 不是datetime 中的.267000,而是.266666~,因为datetime 精确到1/300 秒。

因此,当您将 datetime 转换为具有 4 或更高精度的 datetime2 时,将正确表示 1/300 秒。因此267 在datetime2(7) 中为datetime = .2666667。

如果您想要267,请使用datetime2(3) 而不是datetime2(7)。

关于 2014 年(及之前)SQL Server 的注意事项曾经错误地将 .267 转换为 267000 以获取较新的日期和类型数据类型。这在 SQL Server 2016 中已更改。请参阅Breaking Changes in SQL Server 2016 (13.x)。

【讨论】:

  • 好的,谢谢,所以当将 datetime 转换为 datetime2 时(不指定精度)可能会给你另一个值。实际上这有点奇怪,因为 MS 日期时间规范说准确度是“四舍五入到 0.000、0.003 或 0.007 秒的增量”。如果是这种情况,它应该非常适合 datetime2。
  • “可能会给你另一个值” 不,它给你的是精确的值,而不是另一个值。 datetime 值 2021-01-01T10:00:00.267 和 datetime2(7) 值 2021-01-01T10:00:00.2666667 是 相同 精确值,因为这两种数据类型都尽可能准确地表示 2/300 秒,@Stig .
  • 1/300 != 0.003000 @Stig .... 1/300 = 0.003333333~ 就像 2/600
  • 他们 ARE 是平等的,@Stig ... 这不值得讨论,这是基本的数学。同样1/300 = 0.0033333~ 不是0.0030000(后者是3/1000)。
  • 看来我无法说服你1/300 != 3/1000 这里,@Stig。我已经解释过了,如果你不喜欢这个原因,因为这就是数学和准确性的工作原理,那么我在这里帮不了你;你的理解是有缺陷的。我可以向你保证,如果我有 1/3 的值并将精度从小数点后 1 位扩展到 7,我不会期望 0.3000000 因为它是错误的。
【解决方案2】:

DATETIMEFROMPARTS 返回一个datetime,它只精确到 1/300 秒。当您将 datetime 转换为 datetime2(7) 时,小数部分将扩展到 7 的精度。

将DATETIME2FROMPARTS 与所需的精度规格一起使用:

SELECT convert(datetime2, DATETIME2FROMPARTS (2021,2,28,10,11,12,267,3));
SELECT convert(datetime2, DATETIME2FROMPARTS (2021,2,28,10,11,12,2670000,7));

CONVERT 在这里是不必要的,除非你想改变结果的精度。

【讨论】:

    猜你喜欢
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 2017-08-25
    相关资源
    最近更新 更多