5

我有一个 DateTime varchar,格式如下:2005-08-08T00:00:00+01:00。

  1. 这种格式有名字吗?(不是 ISO8601。是 RFC3339 吗?)
  2. 如何使用 Transact-Sql 将其转换为 DateTime?

编辑 这是一个摘要答案,由其他人输入拼凑而成:

  1. ISO8601,与 UTC 有时间偏移。如果是 UTC,它将以“Z”而不是“+01:00”结尾。 维基百科
  2. 您可以将其转换为当地时间或 UTC,如下所示:

    声明@d VARCHAR(25) 设置@d = '2007-08-08T00:01:00+01:00' 设置@d = '2007-08-08T00:01:00-01:00' 设置@d = ' 2007-08-08T00:01:00+05:30'

    选择 @d 作为输入,CONVERT(DATETIME, LEFT(@d, 19), 126) 作为 LocalDate , DATEADD(MINUTE , -CAST((SUBSTRING(@d, 20, 1) + RIGHT(@d, 2)) 作为INT) , DATEADD(HOUR ,-CAST(SUBSTRING(@d, 20, 3) AS INT) , CONVERT(DATETIME, LEFT(@d, 19), 126))) as UtcDate WHERE @d LIKE ' _ - - _T__ : : [+-] : '

结果:

Input                     LocalDate               UtcDate
------------------------- ----------------------- -----------------------
2007-08-08T00:01:00+01:00 2007-08-08 00:01:00.000 2007-08-07 23:01:00.000

2007-08-08T00:01:00-01:00 2007-08-08 00:01:00.000 2007-08-08 01:01:00.000

2007-08-08T00:01:00+05:30 2007-08-08 00:01:00.000 2007-08-07 18:31:00.000
4

4 回答 4

11

在 SQL Server 2008中,您可以使用datetimeoffset数据类型。

SELECT [Result] = CONVERT(datetimeoffset, '2005-08-08T00:01:00+01:00', 127)

输出:

Result
----------------------------------
2005-08-08 00:01:00.0000000 +01:00

在 SQL Server 2005及更早版本中,您可以计算 UTC 日期和偏移量:

SELECT [LocalDate], [OffsetMinutes], [UtcDate]
FROM
(
    SELECT [IsoDate] = '2007-08-08T00:01:00+01:00'
) A
OUTER APPLY
(
    SELECT [LocalDate] = CONVERT(datetime, LEFT([IsoDate], 19), 126)
    , [OffsetMinutes] =
        CASE SUBSTRING([IsoDate], 20, 1)
            WHEN '+' THEN +1
            WHEN '-' THEN -1
        END
        * DATEDIFF(minute, 0,
            CAST(SUBSTRING([IsoDate], 21, 5) + ':00' AS datetime))
    WHERE [IsoDate] LIKE '____-__-__T__:__:__[+-]__:__'
) B
OUTER APPLY
(
    SELECT [UtcDate] = DATEADD(minute, -[OffsetMinutes], [LocalDate])
) C

输出:

LocalDate               OffsetMinutes UtcDate
----------------------- ------------- -----------------------
2007-08-08 00:01:00.000 60            2007-08-07 23:01:00.000
于 2012-04-24T15:17:07.743 回答
2

其 ISO8601 时区 Z

采用

SELECT CONVERT(datetime,'2005-08-08T00:00:00',126)

MSDN 说明

编辑:我认为这与我最初认为 tSql 会接受的最后区域有关,但事实证明它不会。

于 2012-04-24T15:07:35.457 回答
2

你可以用一种非常丑陋的方式来做,首先获取日期,然后获取时间并将偏移量添加为小时:

declare @d varchar(50)
set @d = '2005-08-08T00:00:00+01:00'

select Convert(datetime, left(@d, 10)) 
    + DateAdd(hour, Cast(substring(@d, 21, 2) as int), convert(datetime, substring(@d, 12, 8)))

或合并版本:

SELECT DateAdd(hour, Cast(substring(@d, 21, 2) as int), CONVERT(datetime, LEFT(@d, 19) ,127))

Final Result:
2005-08-08 01:00:00.000

如果您不需要偏移量,则:

declare @d varchar(50)
set @d = '2005-08-08T00:00:00+01:00'

select Convert(datetime, left(@d, 10)) 
    +  convert(datetime, substring(@d, 12, 8))

Result:
2005-08-08 00:00:00.000
于 2012-04-24T15:27:05.323 回答
0

根据所选答案, datetimeoffset 是一个很好的解决方案。但是,要小心带有内置函数的 sql server 端。(我试图将此作为评论粘贴到已接受的答案中,但它不会格式化代码示例)

select GETDATE(), CONVERT(datetimeoffset, GETDATE(), 127), CONVERT(varchar, convert(datetimeoffset, getdate(), 127)) 
-- Ugg! a SQL Server Bug!!!
-- 2013-08-16 12:54:54.090  2013-08-16 12:54:54.0900000 +00:00  2013-08-16 12:54:54.0900000 +0

select GETUTCDATE(),convert( datetimeoffset, GETUTCDATE(), 127), convert(varchar, convert( datetimeoffset, GETUTCDATE(), 127)) 
-- 2013-08-16 16:54:54.090  2013-08-16 16:54:54.0900000 +00:00  2013-08-16 16:54:54.0900000 +0
于 2013-08-16T17:07:47.480 回答