【问题标题】:SQL: Using DATEADD with bigintsSQL:将 DATEADD 与 bigint 一起使用
【发布时间】:2013-02-22 18:05:23
【问题描述】:

我有一些 SQL 可以将 javascript 日期转换为 SQL 日期,效果很好。但是,我遇到了一些太大并导致异常的数据:

将表达式转换为数据类型int的算术溢出错误

这里是有问题的 SQL:

  DATEADD(MILLISECOND, cast(569337307200000 as bigint) % 1000, DATEADD(SECOND, cast(569337307200000 as bigint) / 1000, '19700101'))

我在 SQL Server 2008 上运行它。

【问题讨论】:

  • 你不能将javascript UTC日期作为字符串传递吗?解析和阅读会更容易......
  • 该数据是否有效?如果我在 JS 控制台中输入new Date(569337307200000),它会显示Mon Aug 01 20011 05:00:00 GMT+0100。您极不可能处理 18,000 年后的日期。
  • 是的,客户不应该接受这个输入,但我正在处理一个遗留迁移项目:-)

标签: sql sql-server-2008


【解决方案1】:

只需分两步完成有问题的DATEADD,从较粗的时间单位(秒、分钟、小时等)开始,然后再返回到细粒度的时间单位。

避免达到几周和几个月的水平,因为这需要实际的日历计算,我们希望系统能够处理。

下面的示例需要在给定(可能)大电流持续时间(以毫秒为单位)的情况下计算开始时间。

-- large durations can overflow the integer argument needed for DATEADD

-- so do as two steps subtracting minutes (60000ms) and then remaining milliseconds.

DATEADD(ms, -large_duration_ms%60000, DATEADD(minute, -large_duration_ms/60000, GETDATE()))

【讨论】:

    【解决方案2】:

    根据MSDN,在DATEADD (datepart , number , date )

    number 是一个表达式,可以解析为添加的 int 到日期的日期部分。用户定义的变量是有效的。如果你 指定带有小数的值,小数被截断并且 没有四舍五入。

    另请注意,即使您将数字作为整数给出,根据您的日期和日期部分,它也可能会溢出日期的最大范围,即 sql server 2008 的 31-12-9999

    数字必须是整数。这是Test Demo

    【讨论】:

    • 是的,我知道这一点,那么将其转换为 sql 日期的解决方案是什么。
    • 在你的情况下,你根本做不到。因为即使您通过将毫秒转换为(比如说)小时来避免 int 溢出问题,因为它大于 70389504(小时差异 '19700101' 和 '99991231' ),它会溢出 sql server 的最大可能日期。 Check this demo to understand
    • 同意,OP 中的方法适用于高达2147483647999 的数字,即2038-01-19 03:14:08。除此之外,他们将需要考虑分解为(例如)小时和毫秒。问题中的那个数字显然是一个错误输入的日期,应该被客户验证拒绝。
    • 是的,不幸的是我正在转换旧数据库。如果默认为最大值,我将不得不添加一个 SQL。
    【解决方案3】:

    我解决整数溢出问题的一种方法是从 microtime unix 时间戳中减去一个更新的日期。

    DATEADD(s, (CreationTimeStamp/1000-1384128000), '2013-11-11') AS CreateDate,
    

    这不会解决 OP 的问题,因为它们仍然会溢出日期列上的最大值。

    【讨论】:

      【解决方案4】:

      我有同样的问题,我想满足 mssql 的日期时间范围

      • 最小日期时间:1753-01-01 00:00:00.000 (-6847804800)
      • 最大日期时间:9999-12-31 23:59:59.997 (253402300799)

      为了实现这一点,我找到的唯一解决方案是循环使用带有 int 范围值的 DATEADD。

      所以基于这个答案:https://stackoverflow.com/a/2904294/687490

      CREATE FUNCTION dbo.fn_ConvertToBigDateTime (@Datetime BIGINT)
      RETURNS DATETIME
      AS
      BEGIN
          DECLARE @result datetime = Convert(datetime, '01/01/1970');
      
          DECLARE @LocalTimeOffset BIGINT
                 ,@AdjustedLocalDatetime BIGINT
                 ,@MinIntValue INT
                 ,@MaxIntValue INT
                 ,@RemainingSeconds BIGINT;
      
          -- define int limit
          SET @MinIntValue = -2147483648;
          SET @MaxIntValue = 2147483647;
      
          -- compute the datetime with the offset
          SET @LocalTimeOffset = DATEDIFF(second,GETDATE(),GETUTCDATE())
          SET @AdjustedLocalDatetime = @Datetime - @LocalTimeOffset
      
          -- going to the future
          WHILE(@AdjustedLocalDatetime>@MaxIntValue)
          BEGIN
              SET @AdjustedLocalDatetime = @AdjustedLocalDatetime - @MaxIntValue;
              SELECT @result = Convert(datetime, dateadd(ss, @MaxIntValue,@result));
          END
      
          -- going back in the past
          WHILE(@AdjustedLocalDatetime<@MinIntValue)
          BEGIN
              SET @AdjustedLocalDatetime = @AdjustedLocalDatetime - @MinIntValue;
              SELECT @result = Convert(datetime, dateadd(ss, @MinIntValue,@result));
          END
      
          RETURN (SELECT DATEADD(second,@AdjustedLocalDatetime, @result))
      END;
      

      然后您可以使用 :

      测试该功能
      select dbo.fn_ConvertToBigDateTime(-6847804800) as 'min datetime', 
      dbo.fn_ConvertToBigDateTime(253402300799) as 'max datetime'
      

      希望它会有所帮助。

      【讨论】:

      • 那个原始答案有夏令时/夏令时的问题,我猜这个函数有同样的问题?
      【解决方案5】:

      我也遇到过这个问题。在我的sql语句中,当日期时间值为null时出现错误。

      我的解决方案是使用“CASE When”检查日期时间值是否为空。只有当它不为空时才运行算术,问题就解决了。

      【讨论】:

        猜你喜欢
        • 2016-08-05
        • 1970-01-01
        • 2019-11-15
        • 1970-01-01
        • 2011-01-11
        • 1970-01-01
        • 1970-01-01
        • 2014-07-18
        • 2011-02-16
        相关资源
        最近更新 更多