你在这里确实有一个模棱两可的问题,但这不是先有鸡还是先有蛋的问题。
您缺少的信息是“什么定义了一天?” 我知道,这听起来很疯狂,但“一天”并不是一个普遍的概念。这是一个本地的。
只需一分钟,抛开时区、DST 和 UTC 的问题。如果我问你,“我们现在离早上 8 点还有多少小时?” 你可以给我两个不同的答案。现在是晚上 7 点,所以您可能会说“11 小时”——因为这是我们从今天早上 8 点开始的时间。但我也可以说“13 小时”——因为那是我们从明天早上 8 点开始的时间。现在在这个非常简单的示例中,您可以通过两种不同的方式之一来消除歧义。您可能会说“最后一个早上 8 点”或“下一个早上 8 点”。或者你可以说“无论今天发生什么” 。
现在回到UTC的概念。什么是“UTC 日”?好吧,我们知道它是 24 小时,因为 UTC 不遵循任何夏令时。但是说它运行“午夜到午夜 UTC”并不是一个非常有意义的衡量标准。当然,有些地方使用了这个定义(例如,StackOverflow 的统计引擎)。但对于大多数人来说,我们想到的是我们自己当地时间的“今天”。
所以我真的不能说“无论今天上午 8 点发生了什么”。您拥有的唯一日期测量是 UTC 日期。您将不知道应该查看哪个本地日期。让我们举一个真实的例子:
- 我住在亚利桑那州凤凰城,所以我的时区偏移量是 UTC-7。我们这里没有夏令时。
- 现在是当地时间 2013 年 6 月 14 日晚上 7 点。
- 那是 2013 年 6 月 15 日,世界标准时间凌晨 2 点。
现在我把那个时间记录在数据库里,后来我问:
- “我们离亚利桑那时间早上 8 点还有多远?”
- 根据我掌握的信息,我不知道我应该寻找 6 月 14 日上午 8 点还是 6 月 15 日上午 8 点。只有后者属于同一 UTC 日期,但我当然可能对其中任何一个感兴趣。
如果您可以在业务逻辑中决定上一次还是下一次,那么您可以解决这个问题。只需将 UTC 日期时间转换为本地时区。然后向前或向后滚动到所需时间。如果您的时区有 DST,并且您在此过程中跨越了过渡日期,则可以对此进行调整。
您也可以选择两者中最近的时间,但这当然取决于您的业务逻辑。
另一种方法是使用您要比较的 UTC 时间来确定您今天所在的本地。所以在我上面的例子中,亚利桑那州当地的6 月 14 日从 6 月 13 日 17:00 UTC 到 6 月 14 日 17:00 UTC。
总而言之,您想知道“DST 中的上午 8 点围绕这个 UTC 日期时间吗?”,如果没有更多信息,您无法回答这个问题,无论是上午 8 点的日期,还是要遵循的一些逻辑关系,其中有几个选项可用。选择适合您需求的策略。
更新
你在评论中问:
我怎么知道现在 UTC 是否在 X 时区的 dst 中,以便我可以相应地调整?
这是datetimeoffset
类型可以提供帮助的地方。您不仅想跟踪“DST 是否有效”,还想跟踪目标时区的精确偏移量,包括任何可能有效的 DST。区别是微妙的,但它归结为跟踪一个完整的偏移量,而不仅仅是一个布尔值是/否。
所以,让我们假设我住在纽约市。查看该网站,我们知道美国东部时间于当地时间 2013 年 3 月 10 日凌晨 2 点生效,并将于当地时间 2013 年 11 月 3 日凌晨 2 点恢复到美国东部标准时间。
所以我们有以下内容:
UTC Local datetimeofffset
2013-03-10T05:00:00Z 2013-03-10T00:00:00-05:00
2013-03-10T06:00:00Z 2013-03-10T01:00:00-05:00
2013-03-10T07:00:00Z 2013-03-10T03:00:00-04:00 <--- transition
2013-03-10T08:00:00Z 2013-03-10T04:00:00-04:00
...
2013-11-03T04:00:00Z 2013-11-03T00:00:00-04:00
2013-11-03T05:00:00Z 2013-11-03T01:00:00-04:00
2013-11-03T06:00:00Z 2013-11-03T01:00:00-05:00 <--- transition
2013-11-03T07:00:00Z 2013-11-03T02:00:00-05:00
现在请注意,如果去掉偏移量,则只有一个单向函数。换句话说,您始终可以为 UTC 时间确定正确的本地时间,但除非您知道回退转换期间的偏移量(或者除非您愿意忍受歧义),否则您不能朝另一个方向发展。
所以从UTC到本地时间的算法应该是这样的:
- 从 UTC 日期时间开始:
2013-11-03T05:30:00Z
- 应用标准偏移 (-5)
2013-11-03T00:30:00-05:00
- 应用采光偏移 (-4)
2013-11-03T01:30:00-04:00
- 根据时区规则,哪一个是有效的?
- 在这种情况下,日光偏移是有效的。
- 您的时区数据应该包含这些信息。
- 如果不是,那么您需要重新考虑时区表的来源。
让我们在另一个 1:30 时间再试一次:
- 从 UTC 日期时间开始:
2013-11-03T06:30:00Z
- 应用标准偏移 (-5)
2013-11-03T01:30:00-05:00
- 应用采光偏移 (-4)
2013-11-03T02:30:00-04:00
- 根据时区规则,哪一个是有效的?
- 在这种情况下,标准偏移量是有效的。
- 我们怎么知道?因为 -4 是日光偏移,并且 DST 应该在当地时间 2:00 结束。我们有 2:30 本地时间与该偏移量相关联,因此只有标准时间在该时区有效。
那么你可以从UTC转换为本地吗?是的。总是。
但是您还说另一列中的本地值就像8AM
. 因此,如果是1:30AM
,那么您肯定会在回退过渡期间产生歧义。没有办法解决这个问题,只能选择一个。
有时,您可能只想选择其中一个,但有时您可能想出错。有时您可能希望让您的用户选择他们感兴趣的两个中的哪一个。看到如下对话框并非闻所未闻:
DAYLIGHT SAVING TIME
We're sorry, but there are two different instances of 1:30 AM on this day.
Which did you mean?
[1:30 AM Eastern Daylight Time] [1:30 AM Eastern Standard Time]
...那些是按钮,如果你不知道的话。:)