【问题标题】:How to convert a DateTime string to a DateTime in SQL Server如何在 SQL Server 中将 DateTime 字符串转换为 DateTime
【发布时间】:2012-05-05 06:01:48
【问题描述】:

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

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

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

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

    DECLARE @d VARCHAR(25) SET @d = '2007-08-08T00:01:00+01:00' SET @d = '2007-08-08T00:01:00-01:00' SET @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)) AS INT) , DATEADD(小时 ,-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

【问题讨论】:

  • 是的,我使用 google 找到了该页面。但是在那里找不到我的格式。
  • 值得注意的是,您的 SUBSTRING() 语句删除了时区的分钟部分,这意味着它在相对于 UTC 不是整小时的时区中是不正确的。例如印度是 ​​UTC+5:30。
  • 哦,如果格式类似于 2005-08-08T00:00:00-01:00,即偏移量是负数而不是正数,那么您的结果将不正确。
  • Rory - 当时区不是整小时时,我已经编辑了 sql 以正确计算 utc,但是当偏移量为负时,我看不到计算有任何问题 - 请参阅上面的结果跨度>

标签: tsql sql-server-2005 datetime-format


【解决方案1】:

在 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

【讨论】:

  • 谢谢,但是数据库是Sql Server 2005,我需要把它转换成DateTime
  • 当然,你是对的。我无法将字符串中的所有信息直接转换为 DateTime。时区必须存储在其他地方(如果需要)
  • 好的。我为 SQL Server 2005 添加了一个解决方案
  • 哇!这里发生了很多事情,但我刚刚意识到的主要事情是@bluefeet 和我一直在添加时区,而我们应该减去它!
【解决方案2】:

其 ISO8601 与 Z 时区

使用

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

MSDN Explanation

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

【讨论】:

  • 刚刚在 sql server 2005 和 2008 中测试过,但失败了
  • 考虑到 `SELECT CONVERT(date,'2005-08-08T00:00:00+01:00',127) 确实有效,这很奇怪
  • 我希望 date 会起作用,因为当 datetime 没有时它会忽略时区,我应该指定 Sql Server 2005。“类型 date 不是定义的系统类型。” 2005年
  • 嗯,上面的链接提到了一些关于 127 类型的内容,但并不表示它不会转换为日期时间......
【解决方案3】:

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

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

【讨论】:

  • 思考这个问题,以及 Anthony Faull 的回答。该字符串包含日期时间和时区,但 Sql Server 2005 只能存储日期时间。所以我必须删除时区,或者将其转换为我决定将 DateTimes 存储在 (GMT) 中的时区
  • 这是一种更简洁的方法:SELECT DateAdd(hour, Cast(substring(@d, 21, 2) as int), CONVERT(datetime, LEFT(@d, 19) ,127))。我建议你编辑你的答案...
  • 合并的那个是我用的那个。它将时间转换为 GMT 以存储在数据库中(我丢失了它设置的时区,但没关系)。谢谢
  • 这里要小心。合并版本应该减去偏移量,而不是添加它
【解决方案4】:

根据所选答案,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

【讨论】:

  • 如果你演示的问题是转换为varchar时字符串被截断,那是因为你没有指定varchar的长度,sql server默认为30个字符。 msdn.microsoft.com/en-us/library/ms176089.aspx
  • 实际上,我试图证明的是使用 datetimeoffset 转换的 GETDATE() 应用 00:00 而不是正确的时区格式。您可以在 GETDATE() 和 GETUTCDATE() 之间使用 datediff 并手动构建字符串,但人们会认为 SQL Server 在使用 convert 模式 127 时会在转换中正确处理偏移量。
  • Sql server 在从 datetime 转换为 datetimeoffset 时无法推断偏移量,因为该信息未存储在 datetime 结构中。您需要 SYSDATETIMEOFFSET() 函数。见stackoverflow.com/a/8634229/150342
  • 每天学习新东西 :) 我不知道这个功能,但我一定会在未来使用它。
猜你喜欢
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
  • 2016-11-30
  • 2014-03-01
  • 2017-02-07
相关资源
最近更新 更多