【问题标题】:Converting from globalized date/time format (maybe ISO8601) to SQL Server datetime type从全球化日期/时间格式(可能是 ISO8601)转换为 SQL Server 日期时间类型
【发布时间】:2010-11-06 05:18:44
【问题描述】:

是否有字符串格式来表示 SQL 将能够解析并转换为另一个偏移量(例如 EST -> UTC)的日期时间。

我有一个来自用户的字符串,例如:

declare @p1 varchar(50);
declare @utcDateTime datetime;

set @p1 = "2009-06-26 14:30:00.000Z-4:00";   -- could be ISO8601

-- what do I do here to convert @p1?

set @utcDateTime = -- should be "2009-06-26 18:30:00.000"

我希望能够将字符串转换为等效的 UTC 并将其存储在日期时间字段中。这样:

select @ utcDateTime 

应该产生这个:

"2009-06-26 18:30:00.000"

换句话说,给定第一个字符串,我想存储一个值为“2009-06-26 18:30”的日期时间。

此外,我们必须假设服务器与用户不在同一时区(因此我们不能只检测偏移量 datediff(gettime(), getutctime())。

我尝试过使用 convert(...) 和 cast(... as datetime) 但没有成功。

在 SQL Server 2005 中有没有办法做到这一点?

【问题讨论】:

  • 将数据存储为日期时间有什么问题?
  • 给定的字符串无法转换; SQL Server 给出此错误:“从字符串转换日期时间时转换失败。”
  • “可能是 ISO”,还是 ISO?最好选择一种格式。
  • 我的意思是,我可以告诉用户使用哪种格式 - 我会选择 ISO 8601。

标签: sql sql-server-2005 timezone globalization


【解决方案1】:

好的,这是我的尝试 - 这很有趣 :-)

 DECLARE  @datestr varchar(100)

SET @datestr = '2009-06-26 14:30:00.000Z+4:00'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

SET @datestr = '2009-06-26 14:30:00.000Z-4:00'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

SET @datestr = '2009-06-26 14:30:00.000Z+14:00'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

SET @datestr = '2009-06-26 14:30:00.000Z+4:30'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

SET @datestr = '2009-06-26 14:30:00.000Z-4:30'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

SET @datestr = '2009-06-26 14:30:00.000Z+14:30'

SELECT @datestr, DATEADD(mi, -1 * CAST(SUBSTRING(@datestr,25,1)+'1' AS int) *  
    DATEDIFF(mi,'1900-01-01', CAST(SUBSTRING(@datestr,26,5) as datetime)),   
    CAST(LEFT(@datestr,23) as datetime) )

返回:

2009-06-26 14:30:00.000Z+4:00  2009-06-26 10:30:00.000

2009-06-26 14:30:00.000Z-4:00  2009-06-26 18:30:00.000

2009-06-26 14:30:00.000Z+14:00 2009-06-26 00:30:00.000

2009-06-26 14:30:00.000Z+4:30  2009-06-26 10:00:00.000

2009-06-26 14:30:00.000Z-4:30  2009-06-26 19:00:00.000

2009-06-26 14:30:00.000Z+14:30 2009-06-26 00:00:00.000

【讨论】:

  • 甜蜜!这行得通!我希望它看起来不会那么难看,但无论如何。这也要求字符串具有一定的长度 - 但无论如何我都会在途中验证字符串模式。
【解决方案2】:

使用日期时间的一种方式 在窗口中运行它

declare @date varchar(100)
select @date = '2009-06-26 14:30:00.000'

select dateadd(hh,datediff(hh,getdate(),getutcdate()),@date)

输出 2009-06-26 18:30:00.000

最好始终使用 getutcdate() 并将用户偏移量存储在他的个人资料中

SQL Server 2008 具有新的 datetimeoffset 数据类型,这让这变得更容易

现在这是一个适用于您拥有的数据的答案(我还添加了 1/2 小时代码)

这里解释了代码的工作原理:Adding time offsets passed in to a datetime to generate localized datetime

    declare @date varchar(100),@multiplier int

select @date = '2009-06-26 14:30:00.000Z+4:30'
select @multiplier = case when @date like '%+%' then -1 else 1 end


select dateadd(mi, @multiplier *convert(int,right(@date,2)),dateadd(hh
    ,-1 * convert(int,replace(substring(@date,patindex('%z%',@date)+ 1,3),':',''))
    ,left(@date,23)))
go


--2009-06-26 10:00:00.000

declare @date varchar(100),@multiplier int

select @date = '2009-06-26 14:30:00.000Z-4:30'
select @multiplier = case when @date like '%+%' then -1 else 1 end

select dateadd(mi, @multiplier *convert(int,right(@date,2)),dateadd(hh
    ,-1 * convert(int,replace(substring(@date,patindex('%z%',@date)+ 1,3),':',''))
    ,left(@date,23)))
go

--2009-06-26 19:00:00.000

declare @date varchar(100),@multiplier int

select @date = '2009-06-26 14:30:00.000Z+14:30'
select @multiplier = case when @date like '%+%' then -1 else 1 end

select dateadd(mi, @multiplier *convert(int,right(@date,2)),dateadd(hh
    ,-1 * convert(int,replace(substring(@date,patindex('%z%',@date)+ 1,3),':',''))
    ,left(@date,23)))
go

--2009-06-26 01:00:00.000


declare @date varchar(100),@multiplier int
select @date = '2009-06-26 14:30:00.000Z-14:30'
select @multiplier = case when @date like '%+%' then -1 else 1 end

select dateadd(mi, @multiplier *convert(int,right(@date,2)),dateadd(hh
    ,-1 * convert(int,replace(substring(@date,patindex('%z%',@date)+ 1,3),':',''))
    ,left(@date,23)))
go

--2009-06-27 05:00:00.000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多