如何将 SQL Server
datetime
值转换为 datetimeoffset
值?
例如,现有表包含
datetime
值,这些值均位于 “本地” 服务器时间。
SELECT TOP 5 ChangeDate FROM AuditLog
ChangeDate
=========================
2013-07-25 04:00:03.060
2013-07-24 04:00:03.073
2013-07-23 04:00:03.273
2013-07-20 04:00:02.870
2013-07-19 04:00:03.780
我的服务器(发生)(现在,今天)比 UTC 晚四个小时(现在,在美国东部时区,夏令时有效):
SELECT SYSDATETIMEOFFSET()
2013-07-25 14:42:41.6450840 -04:00
我想将存储的
datetime
值转换为 datetimeoffset
值;使用服务器当前的时区偏移信息。
我渴望的价值观是:
ChangeDate ChangeDateOffset
======================= ==================================
2013-07-25 04:00:03.060 2013-07-25 04:00:03.0600000 -04:00
2013-07-24 04:00:03.073 2013-07-24 04:00:03.0730000 -04:00
2013-07-23 04:00:03.273 2013-07-23 04:00:03.2730000 -04:00
2013-07-20 04:00:02.870 2013-07-20 04:00:02.8700000 -04:00
2013-07-19 04:00:03.780 2013-07-19 04:00:03.7800000 -04:00
您可以看到理想的特性:
2013-07-19 04:00:03.7800000 -04:00
\_________________________/ \____/
| |
a "local" datetime the offset from UTC
但实际值是:
SELECT TOP 5
ChangeDate,
CAST(ChangeDate AS datetimeoffset) AS ChangeDateOffset
FROM AuditLog
ChangeDate ChangeDateOffset
======================= ==================================
2013-07-25 04:00:03.060 2013-07-25 04:00:03.0600000 +00:00
2013-07-24 04:00:03.073 2013-07-24 04:00:03.0730000 +00:00
2013-07-23 04:00:03.273 2013-07-23 04:00:03.2730000 +00:00
2013-07-20 04:00:02.870 2013-07-20 04:00:02.8700000 +00:00
2013-07-19 04:00:03.780 2013-07-19 04:00:03.7800000 +00:00
具有无效特征:
2013-07-19 04:00:03.7800000 +00:00
\_________________________/ \____/
^
|
No offset from UTC present
所以我随机尝试其他事情:
SELECT TOP 5
ChangeDate,
CAST(ChangeDate AS datetimeoffset) AS ChangeDateOffset,
DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), ChangeDate) AS ChangeDateUTC,
CAST(DATEADD(minute, DATEDIFF(minute, GETDATE(), GETUTCDATE()), ChangeDate) AS datetimeoffset) AS ChangeDateUTCOffset,
SWITCHOFFSET(CAST(ChangeDate AS datetimeoffset), DATEDIFF(minute, GETUTCDATE(), GETDATE())) AS ChangeDateSwitchedOffset
FROM AuditLog
ORDER BY ChangeDate DESC
结果:
ChangeDate ChangeDateOffset ChangeDateUTC ChangeDateUTCOffset ChangeDateSwitchedOffset
======================= ================================== ======================= ================================== ==================================
2013-07-25 04:00:03.060 2013-07-25 04:00:03.0600000 +00:00 2013-07-25 08:00:03.060 2013-07-25 08:00:03.0600000 +00:00 2013-07-25 00:00:03.0600000 -04:00
2013-07-24 04:00:03.073 2013-07-24 04:00:03.0730000 +00:00 2013-07-24 08:00:03.073 2013-07-24 08:00:03.0730000 +00:00 2013-07-24 00:00:03.0730000 -04:00
2013-07-23 04:00:03.273 2013-07-23 04:00:03.2730000 +00:00 2013-07-23 08:00:03.273 2013-07-23 08:00:03.2730000 +00:00 2013-07-23 00:00:03.2730000 -04:00
2013-07-20 04:00:02.870 2013-07-20 04:00:02.8700000 +00:00 2013-07-20 08:00:02.870 2013-07-20 08:00:02.8700000 +00:00 2013-07-20 00:00:02.8700000 -04:00
2013-07-19 04:00:03.780 2013-07-19 04:00:03.7800000 +00:00 2013-07-19 08:00:03.780 2013-07-19 08:00:03.7800000 +00:00 2013-07-19 00:00:03.7800000 -04:00
---------------------------------- ---------------------------------- ----------------------------------
No UTC offset Time in UTC No UTC offset Time all wrong
它们都没有返回所需的值。
任何人都可以提出一些可以返回我直观想要的东西吗?
SELECT
ChangeDate, --original datetime value
ChangeDate AT TIME ZONE 'Eastern Standard Time' AS ChangeDateOffset
FROM AuditLog
AT TIME ZONE
会考虑夏令时在转换日期时是否生效。即使它在 “东部标准时间” 中显示“标准”,它也会为您提供夏令时:
ChangeDate ChangeDateOffset
----------------------- ------------------------------
2019-01-21 09:00:00.000 2019-01-21 09:00:00.000 -05:00
2019-02-21 09:00:00.000 2019-02-21 09:00:00.000 -05:00
2019-03-21 09:00:00.000 2019-03-21 09:00:00.000 -04:00 <-- savings time
2019-04-21 09:00:00.000 2019-04-21 09:00:00.000 -04:00 <-- savings time
2019-05-21 09:00:00.000 2019-05-21 09:00:00.000 -04:00 <-- savings time
2019-06-21 09:00:00.000 2019-06-21 09:00:00.000 -04:00 <-- savings time
2019-07-21 09:00:00.000 2019-07-21 09:00:00.000 -04:00 <-- savings time
2019-08-21 09:00:00.000 2019-08-21 09:00:00.000 -04:00 <-- savings time
2019-09-21 09:00:00.000 2019-09-21 09:00:00.000 -04:00 <-- savings time
2019-10-21 09:00:00.000 2019-10-21 09:00:00.000 -04:00 <-- savings time
2019-11-21 09:00:00.000 2019-11-21 09:00:00.000 -05:00
2019-12-21 09:00:00.000 2019-12-21 09:00:00.000 -05:00
至于如何避免对字符串进行硬编码Eastern Standard Time
,并使用服务器的当前时区?你太棒了。 SQL Server 2016 之前的原始答案
datetime
。
例如,相同的查询:
SELECT ToDateTimeOffset('2013-07-25 15:35:27', -240) -- -240 minutes
SELECT ToDateTimeOffset('2013-07-25 15:35:27', '-04:00') -- -4 hours
均返回:
2013-07-25 15:35:27.0000000 -04:00
注意:
ToDateTimeOffset
的偏移参数可以是:
integer
a
string
{+|-}TZH:THM
格式)我们需要服务器当前的 UTC 偏移量
integer
DATEPART(TZOFFSET, SYSDATETIMEOFFSET())
DATEDIFF(minute, GETUTCDATE(), GETDATE())
双双回归-240
将其插入到
TODATETIMEOFFSET
函数中:
SELECT ToDateTimeOffset(
'2013-07-25 15:35:27',
DATEPART(TZOFFSET, SYSDATETIMEOFFSET()) --e.g. -240
)
返回我想要的datetimeoffset
值:
2013-07-25 15:35:27.0000000 -04:00
总而言之现在我们可以有一个更好的函数将日期时间转换为日期时间偏移:CREATE FUNCTION dbo.ToDateTimeOffset(@value datetime2)
RETURNS datetimeoffset AS
BEGIN
/*
Converts a date/time without any timezone offset into a datetimeoffset value,
using the server's current offset from UTC.
For this we use the built-in ToDateTimeOffset function;
which attaches timezone offset information with a datetimeoffset value.
The trick is to use DATEDIFF(minutes) between local server time and UTC
to get the offset parameter.
For example:
DATEPART(TZOFFSET, SYSDATETIMEOFFSET())
returns the integer
-240
for people in EDT (Eastern Daylight Time), which is 4 hours (240 minutes) behind UTC.
Pass that value to the SQL Server function:
TODATETIMEOFFSET(@value, -240)
*/
RETURN TODATETIMEOFFSET(@value, DATEPART(TZOFFSET, SYSDATETIMEOFFSET()))
END;
使用示例
SELECT TOP 5
ChangeDate,
dbo.ToDateTimeOffset(ChangeDate) AS ChangeDateOffset
FROM AuditLog
ChangeDate ChangeDateOffset
======================= ==================================
2013-07-25 04:00:03.060 2013-07-25 04:00:03.0600000 -04:00
2013-07-24 04:00:03.073 2013-07-24 04:00:03.0730000 -04:00
2013-07-23 04:00:03.273 2013-07-23 04:00:03.2730000 -04:00
2013-07-20 04:00:02.870 2013-07-20 04:00:02.8700000 -04:00
2013-07-19 04:00:03.780 2013-07-19 04:00:03.7800000 -04:00
如果内置函数能够这样做,那就太理想了:
TODATETIMEOFFSET(value)
而不是必须创建“过载”
:dbo.ToDateTimeOffset(value)
注意
:任何代码都会发布到公共领域。无需归属。
要从本地时间转换为具有当前时间偏移的日期时间偏移似乎需要一些技巧。可能有更简单的方法,但这似乎可以做到;
SELECT ChangeDate,
CONVERT(DATETIMEOFFSET, CONVERT(VARCHAR, ChangeDate, 120) +
RIGHT(CONVERT(VARCHAR, SYSDATETIMEOFFSET(), 120), 6), 120)
FROM AuditLog;
CREATE FUNCTION LOCALIFY(@dt DATETIME)
RETURNS DATETIMEOFFSET AS
BEGIN
RETURN CONVERT(DATETIMEOFFSET,
CONVERT(VARCHAR, @dt, 120) +
RIGHT(CONVERT(VARCHAR, SYSDATETIMEOFFSET(), 120), 6), 120)
END;
...然后就...
SELECT ChangeDate, dbo.LOCALIFY(ChangeDate) FROM AuditLog;
您可以将
AT TIME ZONE
SELECT CURRENT_TIMEZONE_ID();
DECLARE @tests TABLE (dt DATETIME2(0) NOT NULL);
INSERT INTO @tests (dt) VALUES
('2023-03-11 12:00:00'),
('2023-03-12 12:00:00'),
('2023-11-04 12:00:00'),
('2023-11-05 12:00:00');
SELECT dt, dt AT TIME ZONE CURRENT_TIMEZONE_ID()
FROM @tests;
从OP开始时间有点晚,但是这个线程有助于注意将
datetime
转换为
我已经使用了一些功能,但也建议使用默认设置为
sysdatetimeoffset()
的字段,以便插入项目时(当前时间戳)将相对于插入时间而言。然后如果修改是如果需要,更新可以使用程序中源中的 TZ。这在
OData v4
交易中变得尤为明显,它需要
datetimeoffset
。
我认为您必须将
DATEPART(TZOFFSET,SYSDATETIMEOFFSET())
乘以