【问题标题】:TSQL Datetime conversion looses a period of timeTSQL Datetime转换丢失一段时间
【发布时间】:2018-04-28 23:44:10
【问题描述】:

我正在使用 MsSQL Server 玩了几天,在将日期时间转换为/从小数时偶然发现了一个奇怪的行为。

SELECT [date] = GETDATE()

, [as decimal] = CAST(GETDATE() AS decimal)
, [from decimal] = CAST(CAST(GETDATE() AS decimal) AS datetime)

, [as float] = CAST(GETDATE() AS float)
, [from float] = CAST(CAST(GETDATE() AS float) AS datetime)

--                                  should be: 2009-08-15
, [from stored float] = CAST(CAST('40039.9583333333' AS float) AS datetime)

当我在不添加任何特定内容的情况下转换日期时间时,小数点将按照我定义的小数点 (18, 0) 进行处理。 So there is a data loss in some way.

如果我直接将浮点数转换回从日期时间转换的日期时间(如我的查询的第 7 行所示),一切都很好。

但是当我从数据库表中加载一个值时,例如 40039.9583333333,它肯定是根据用户输入 (2009-08-15) 计算出来的,并将其转换回日期时间,它会增加一天。

我找不到任何关于这次损失的具体信息。


有人能够描述这种奇怪行为背后的问题吗? 如果可能的话: 添加一个如何正确进行这些转换的示例?

谢谢。

【问题讨论】:

  • 您的代码运行良好。当我将 40039.9583333333 转换为日期时间时,它确实给了我 2009-08-16。你是从哪里得到这个值的?
  • 由于 0.0 将是 '19000101 00:00:00',我会确保您从该数据库加载的值处于相同的比例。基本上,你确定 40039.9583333333 是 '2009-08-15'?
  • 我不能 100% 确定,因为数据来自我不知道源代码的程序。但是15.08.2009(德语格式)是用户插入的,从中计算出的数字是40039.9583333333
  • 在SQL中40039.9583333333SELECT CAST(CAST('2009-08-16 23:00' AS DATETIME) AS FLOAT)的结果

标签: sql tsql datetime type-conversion sql-server-2014


【解决方案1】:

您在数据库中的输入源是什么?根本问题可能是日期的起始参考点。

例如:从在线阅读,在 Excel 中,日期值“1900-01-01”在数字上等于 1。

但是,在 SQL Server 中,日期值“1900-01-01”在数字上等于 0。

SELECT CAST(CAST('1900-01-01' AS DATETIME) AS FLOAT)

【讨论】:

  • SELECT CAST(CAST('2009-08-15' AS DATETIME) AS FLOAT) 是 40038,所以我认为你的方法是正确的。这可能是某种奇怪的时区问题吗?
  • 这真的取决于源代码是如何工作的。到目前为止,所有迹象都表明应用程序的算法和 SQL Server 之间的扩展存在差异。
【解决方案2】:

在 SQL Server 中40039.9583333333SELECT CAST(CAST('2009-08-16 23:00' AS DATETIME) AS FLOAT) 的结果

您应该检查输入。检查正在使用哪个比例/代码来计算存储在表中的值。

【讨论】:

    【解决方案3】:

    我使用了您指定的值 '2009-08-15' 并将其转换为十进制和浮点数,这导致两者的值都是 40038。我使用此值转换回日期时间,十进制和浮点数都返回“2009-08-15 00:00:00.000”。

    值 40039.9583333333 的结果是,正如 Renan 刚刚发布的 :),'2009-08-16 22:59:59.997'。

    我会质疑它是否“绝对是根据用户输入计算的 (2009-08-15)”,因为情况似乎并非如此。它的意义远不止共享。

    -- Microsoft SQL Server 2014 - 12.0.4100.1 (X64)
    
    DECLARE @dt datetime = '2009-08-15'
    
    SELECT CAST(@dt AS decimal) -- 40038
    SELECT CAST(@dt AS float) -- 40038
    
    DECLARE @dec1 decimal = 40038;
    SELECT CAST(@dec1 AS datetime) -- 2009-08-15 00:00:00.000
    DECLARE @flo1 float = 40038;
    SELECT CAST(@flo1 AS datetime) -- 2009-08-15 00:00:00.000
    
    DECLARE @dec2 decimal = 40039.9583333333;
    SELECT CAST(@dec2 AS datetime) -- 2009-08-17 00:00:00.000
    DECLARE @flo2 float = 40039.9583333333;
    SELECT CAST(@flo2 AS datetime) -- 2009-08-16 22:59:59.997
    

    【讨论】:

      猜你喜欢
      • 2017-05-30
      • 2015-12-07
      • 2012-06-09
      • 2022-01-24
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      相关资源
      最近更新 更多