使用DateTime2

时间:2016-11-29 23:37:10

标签: sql-server tsql datetime

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

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仍然截断上述内容的功能?

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

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数据类型转换为日期时间数据类型   在超出范围的价值。

投射到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数据类型转换为日期时间数据类型   导致了超出范围的价值。

我假设0被视为DateTime数据类型并有效地将其投放到DateTime

尝试使用0DateTime2转换为CAST(0 AS DATETIME2)会给我这个错误

  

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

最后,我想在表中使用这些作为持久列,这些列与DateTime数据类型配合得很好,但DateTime2

不那么容易

3 个答案:

答案 0 :(得分:2)

您应该使用某个特定的基准日期而不是00可以隐式转换为datetime类型。对于datetime2,不允许进行此类隐式转换。此外,基准日期应为datetime2类型。然后DATEDIFFDATEADD将使用datetime2值。

使用显式基准日期的另一个原因是您需要将此基准日期作为一年中的第一天,并且00:00:00时间使公式正常工作。隐含的开始日期,例如转换为0的{​​{1}}或转换为datetime的{​​{1}}现在也具有这些属性,但您是否真的想依赖该类型的内部细节实施?最好明确说明这些事情,这样可以让新人更易于理解。

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

示例1 - 工作

''

示例2 - 工作

datetime2

示例3 - 无效

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;
  

向'datetime'列添加值会导致溢出。

它不起作用,因为文字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; 转换为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

示例4 - 作品

datetime

答案 1 :(得分:1)

尝试使用:

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;

答案 2 :(得分:1)

我发现如果我使用转换而不是使用CAST('DateTimeData'作为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;

感谢您的帮助。