夏令时和 UTC 时间

Posted

技术标签:

【中文标题】夏令时和 UTC 时间【英文标题】:Daylight savings time and UTC time 【发布时间】:2016-02-06 19:55:23 【问题描述】:

我们使用一个以 UTC 时间保存时间戳的程序。我们是犹他州的本地公司,因此会受到夏令时的影响。

例如,如果我们现在接到一个电话,它是12:52:00 MST,它会在数据库中保存为19:52:00

我首先担心的是明年 DST 将于 2016 年 3 月 13 日再次开始,而我正好在同一时间运行它。 UTC 中的时间戳是 18:52:00 还是保持在 19:52:00

我的第二个问题是如果我将数据库中的日期转换为我的本地时间,那么我必须首先检查它是否是 DST,然后是否需要时间 -6,如果不是,它会是 -7?

所以使用上面的例子:

IsDST = 01:52:00 (-6)
IsNotDST = 12:52:00 (-7)

我认为这是我需要担心必须转换为/从 UTC 转换的事情?

除了上述两个问题之外,我的主要问题。 SQL Server/T-SQL 中是否有任何东西可以为我处理这种转换,还是我需要自己编写所有东西来满足需要?

我已经开始了,但如果有必要,现在需要在 DST 中工作

DECLARE @declared_start_datetime DATETIME, 
        @declared_end_datetime DATETIME, 
        @converted_start_datetime DATETIME, 
        @converted_end_datetime DATETIME

SET @declared_start_datetime = '11/04/2015 07:00:00' -- Hour we open phones
SET @declared_end_datetime = '11/04/2015 18:00:00' -- Hour we close phones
SET @converted_start_datetime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @declared_start_datetime)
SET @converted_end_datetime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @declared_end_datetime)

select @declared_start_datetime as 'Declared Start', 
       @declared_end_datetime as 'Declared End'
select @converted_start_datetime as 'Converted Start',
       @converted_end_datetime as 'Converted End'

【问题讨论】:

你的问题一点都不清楚。你似乎知道GETUTCDATE(),你说你想使用UTC时间戳(不错的选择),你为什么还要处理本地时间戳? 哪个时间是同一时间:12:52:00 MST 还是 MDT?除了注意夏令时在不同时间开始的方式以及不久前发生这种转变之外,还有一个重要的区别。 这些报告将由公司中的其他人员运行,他们将选择运行报告的时间(当地时间)。而且我预示着他们必须自己学习/转换为 UTC 的投诉/强烈反对的数量。所以我需要取他们的当地时间并将它们转换为 UTC 以从数据库中获取正确的记录。 @amit @JBKing 现在正确的时间是 MST (-7) 明年 3 月 13 日凌晨 2:00 如果我的研究是正确的,它将变成 MDT (-6)。 您讲述的“用户故事”是表示或业务层的问题,而不是数据库/存储层的问题。在那边处理。 【参考方案1】:

例如,如果我们现在接到一个电话,它是12:52:00 MST,它会在数据库中保存为19:52:00

我首先担心的是明年 DST 将于 2016 年 3 月 13 日再次开始,而我正是在同一时间运行它。 UTC 中的时间戳会是 18:52:00 还是会保持在 19:52:00

山地标准时间为 UTC-7,美国山地夏令时间为 UTC-6。如果您写出转换中涉及的完整日期、时间和偏移量,那么推理起来要容易得多。这是标准 ISO8601 扩展格式:

2015-11-06T12:52:00-07:00 = 2015-11-06T19:52:00Z
2016-03-13T12:52:00-06:00 = 2016-03-13T18:52:00Z

等式左侧的每个本地时间都标有正确的本地时间和该时间的本地偏移量。然后要到达 UTC(由 Z 标识),您只需从本地时间中减去偏移量。或者,如果这更容易合理化,可以将其视为反转符号并添加。

所以是的,当您在白天时,它会将其存储在18:52:00 UTC。这是正确的行为。

我的第二个问题是如果我将数据库中的日期转换为我的本地时间,那么我必须首先检查它是否是 DST,然后是否需要时间 -6,如果不是,它会是 -7?

是的,但请记住,这是您转换的时间戳所反映的日期和时间。你是否当前在夏令时没有区别。

但是,请记住,如果您能提供帮助,通常应该避免在数据库层进行时区转换。在绝大多数用例中,这是一个应用层问题。

例如,如果您从 .NET 中构建的应用程序写入 SQL Server,则可以使用带有 "Mountain Standard Time" ID 的 TimeZoneInfo 类(用于 MST 和 MDT)。或者,您可以使用带有TZDB 标识符"America/Denver" 的Noda Time 库。

通过使用库,您不必关心 DST 何时开始和停止的所有各种细节,也不必担心它在世界不同地区的历史中是如何变化的。

在极少数情况下,您实际上需要在数据库级别完成时区转换,您当然可以编写自己的存储过程或 UDF(例如链接到的一些问题 cmets),但取决于您的需要,它们可能还不够。通常他们倾向于只编码一组固定的时区转换规则,因此他们不会考虑其他时区或历史变化。

有一些适用于 SQL Server 的通用时区解决方案,但与其他数据库平台不同,没有内置任何内容。我会推荐我的SQL Server Time Zone SupportOSS 项目,如果你搜索还有其他的。但实际上,您应该希望不需要这个,并且应该尽可能在应用层进行转换。

更新:在 SQL Server 2016 CTP 3.1 中,现在通过 AT TIME ZONE 语句内置了对时区的支持。见the CTP announcement for examples。

【讨论】:

谢谢马特。不幸的是,我没有使用应用程序,因此需要以这种方式编写 DST 转换内容。我获取他们提供的日期并检查它是否在 DST 中,然后将日期更改为 6 或 7,然后使用它从数据库中获取值。这是请求的自定义报告。我会检查你提到的时区支持项目。 请记住转换的时间,并且在秋季,转换期间的值可能不明确。例如,2015-11-01T01:30 可能是 2015-11-01T01:30-06:00 OR 2015-11-01T01:30-07:00。您需要决定选择哪个。如果有疑问,大多数情况都需要第一次(白天)发生。尽管有时可以根据其他相关数据来消除歧义。

以上是关于夏令时和 UTC 时间的主要内容,如果未能解决你的问题,请参考以下文章

UTC 时间、时区、夏令时和夏令时切换日期

使用 WinAPI 进行夏令时和 UTC 到本地时间的转换

程序里的国际时区和夏令时

将 UTC 时间戳插入 MySQL - 夏令时时区

将UTC时间转换为PST以获得夏令时?

UTC 是不是遵守夏令时?