【问题标题】:Truncating date + time using DateTime2使用 DateTime2 截断日期 + 时间
【发布时间】:2016-11-30 09:51:34
【问题描述】:

多年来我一直使用这种格式来截断日期和时间

SELECT  DATEADD(HOUR, DATEDIFF(HOUR, 0, '1980-02-05 12:45'), 0) AS Hour ,
        DATEADD(DAY, DATEDIFF(DAY, 0, '1980-02-05 12:45'), 0) AS Day ,
        DATEADD(MONTH, DATEDIFF(MONTH, 0, '1980-02-05 12:45'), 0) AS Month ,
        DATEADD(YEAR, DATEDIFF(YEAR, 0, '1980-02-05 12:45'), 0) AS Year;

但我需要存储很早的日期,例如1400-01-01,因此我可以使用DateTime2

但是我如何支持使用DateTime2 仍然像上面那样截断的能力?

将上面的年份从 1980 更改为 1400 将导致

SELECT  DATEADD(HOUR, DATEDIFF(HOUR, 0, '1400-02-05 12:45'), 0) AS Hour ,
        DATEADD(DAY, DATEDIFF(DAY, 0, '1400-02-05 12:45'), 0) AS Day ,
        DATEADD(MONTH, DATEDIFF(MONTH, 0, '1400-02-05 12:45'), 0) AS Month ,
        DATEADD(YEAR, DATEDIFF(YEAR, 0, '1400-02-05 12:45'), 0) AS Year;

导致将 varchar 数据类型转换为 datetime 数据类型 在一个超出范围的值。

所以投射到DateTime2

SELECT  DATEADD(HOUR, DATEDIFF(HOUR, 0, CAST('1400-02-05 12:45' AS DATETIME2)),0) AS Hour ,
        DATEADD(DAY, DATEDIFF(DAY, 0, CAST('1400-02-05 12:45' AS DATETIME2)),0) AS Day ,
        DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST('1400-02-05 12:45' AS DATETIME2)), 0) AS Month ,
        DATEADD(YEAR, DATEDIFF(YEAR, 0, CAST('1400-02-05 12:45' AS DATETIME2)), 0) AS Year;

将 datetime2 数据类型转换为 datetime 数据类型 导致超出范围的值。

我假设0 被视为DateTime 数据类型并有效地将其转换为DateTime

尝试使用 CAST(0 AS DATETIME2)0 转换为 DateTime2 会出现此错误

不允许从数据类型 int 到 datetime2 的显式转换。

最后,我想将这些用作表中的持久列,这些列在 DateTime 数据类型上工作得很好,但在 DateTime2 上却不那么容易

【问题讨论】:

  • 提示:使用适当的软件(MySQL、Oracle、DB2 等)和版本标记数据库问题很有帮助,例如sql-server-2014。语法和功能的差异通常会影响答案,例如DateFromParts.

标签: sql-server tsql datetime


【解决方案1】:

您应该使用一些特定的基准日期而不是00 可以隐式转换为 datetime 类型。对于datetime2,这种隐式转换是不允许的。此外,基准日期应具有datetime2 类型。然后DATEDIFFDATEADD 将与datetime2 值一起使用。

使用显式基准日期的另一个原因是,您需要此基准日期为一年中的第一天,并有00:00:00 时间才能使公式正常工作。隐式开始日期,例如 0 转换为 datetime'' 转换为 datetime2 现在也有这些属性,但你真的想依赖类型实现的内部细节吗?最好明确说明这些内容,这样可以使新人更容易理解公式。

此外,如果您想使用相同的方法截断到周边界,那么您必须选择一个基准日期,即星期一(如果您的一周从星期一开始)或星期日(如果您的一周从星期日开始) )。公式保持不变,但基准日期很重要。

示例 1 - 有效

DECLARE @VarBase datetime2 = '2000-01-01';
DECLARE @VarValue datetime2 = '1400-02-05 12:45';

SELECT
    DATEADD(HOUR,  DATEDIFF(HOUR,  @VarBase, @VarValue), @VarBase) AS Hour,
    DATEADD(DAY,   DATEDIFF(DAY,   @VarBase, @VarValue), @VarBase) AS Day,
    DATEADD(MONTH, DATEDIFF(MONTH, @VarBase, @VarValue), @VarBase) AS Month,
    DATEADD(YEAR,  DATEDIFF(YEAR,  @VarBase, @VarValue), @VarBase) AS Year;

示例 2 - 有效

SELECT
    DATEADD(HOUR,  DATEDIFF(HOUR,  @VarBase, '1400-02-05 12:45'), @VarBase) AS Hour,
    DATEADD(DAY,   DATEDIFF(DAY,   @VarBase, '1400-02-05 12:45'), @VarBase) AS Day,
    DATEADD(MONTH, DATEDIFF(MONTH, @VarBase, '1400-02-05 12:45'), @VarBase) AS Month,
    DATEADD(YEAR,  DATEDIFF(YEAR,  @VarBase, '1400-02-05 12:45'), @VarBase) AS Year;

示例 3 - 不起作用

SELECT
    DATEADD(HOUR,  DATEDIFF(HOUR,  '2000-01-01', '1400-02-05 12:45'), '2000-01-01') AS Hour,
    DATEADD(DAY,   DATEDIFF(DAY,   '2000-01-01', '1400-02-05 12:45'), '2000-01-01') AS Day,
    DATEADD(MONTH, DATEDIFF(MONTH, '2000-01-01', '1400-02-05 12:45'), '2000-01-01') AS Month,
    DATEADD(YEAR,  DATEDIFF(YEAR,  '2000-01-01', '1400-02-05 12:45'), '2000-01-01') AS Year;

向“日期时间”列添加值导致溢出。

它不起作用,因为文字 2000-01-01 被转换为 datetime,而不是 datetime2

示例 4 - 有效

SELECT
    DATEADD(HOUR,  DATEDIFF(HOUR,  CAST('2000-01-01' AS datetime2), '1400-02-05 12:45'), CAST('2000-01-01' AS datetime2)) AS Hour,
    DATEADD(DAY,   DATEDIFF(DAY,   CAST('2000-01-01' AS datetime2), '1400-02-05 12:45'), CAST('2000-01-01' AS datetime2)) AS Day,
    DATEADD(MONTH, DATEDIFF(MONTH, CAST('2000-01-01' AS datetime2), '1400-02-05 12:45'), CAST('2000-01-01' AS datetime2)) AS Month,
    DATEADD(YEAR,  DATEDIFF(YEAR,  CAST('2000-01-01' AS datetime2), '1400-02-05 12:45'), CAST('2000-01-01' AS datetime2)) AS Year;

【讨论】:

  • 谢谢 - 但我现在有一个问题,它不是确定性的。请参阅我对@MegaTron 线程的评论
  • @ChrisCrowe,很高兴您发现自己使用 CONVERT 而不是 CAST 可以解决问题。
【解决方案2】:

尝试使用:

DECLARE @Default DATETIME2 = CAST('' AS DATETIME2)
SELECT  DATEADD(HOUR, DATEDIFF(HOUR, @Default, CAST('1400-02-05 12:45' AS DATETIME2)), @Default) AS Hour ,
        DATEADD(DAY, DATEDIFF(DAY, @Default, CAST('1400-02-05 12:45' AS DATETIME2)), @Default) AS Day ,
        DATEADD(MONTH, DATEDIFF(MONTH, @Default, CAST('1400-02-05 12:45' AS DATETIME2)), @Default) AS Month ,
        DATEADD(YEAR, DATEDIFF(YEAR, @Default, CAST('1400-02-05 12:45' AS DATETIME2)), @Default) AS Year;

【讨论】:

  • 感谢您的帮助,但我现在有一个问题,这些公式是不确定的,无法持久保存到数据库中。 ALTER TABLE dbo.QuakeRawJSON ADD [Date] AS (dateadd(day,datediff(day,CAST('' AS DATETIME2),origintime),CAST('' AS DATETIME2))) PERSISTED Msg 4936, Level 16, State 1, Line 1 表“QuakeRawJSON”中的计算列“日期”无法持久化,因为该列是不确定的。
【解决方案3】:

我发现如果我使用 Convert 而不是使用 CAST ('DateTimeData' as DateTime2) 它可以是一个确定性的结果。

如本文所述:Cannot persist computed column - not deterministic

ALTER TABLE dbo.QuakeRawJSON
ADD [Date]  AS (DATEADD(DAY,DATEDIFF(DAY, CONVERT(DATETIME2,'',112) 
                ,origintime),CONVERT(DATETIME2,'',112))) PERSISTED;

感谢您的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    • 2015-12-12
    • 2014-08-29
    • 2011-07-25
    相关资源
    最近更新 更多