给定 UTC 时间,获取特定时区是午夜

Posted

技术标签:

【中文标题】给定 UTC 时间,获取特定时区是午夜【英文标题】:Given a UTC time, get a specified timezone's midnight 【发布时间】:2017-08-05 13:06:40 【问题描述】:

请注意,这与this question 不同完全。该问题假定您想要的时间是“现在”,这与任意时间点不同。

我有一个 UTC 感知的日期时间对象,将其命名为 point_in_time(例如 datetime(2017, 3, 12, 16, tzinfo=tz.tzutc()))。

我有一个时区,叫它location(例如'US/Pacific'),因为我关心它在哪里,但是它与 UTC 的时间偏移可能会随着夏令时和什么的。

我想 1) 如果我站在location,请获取point_in_time 的日期, 2) 如果我站在location,则获得该日期的午夜。

===

我尝试简单地使用.astimezone(timezone('US/Pacific')) 然后.replace(hours=0, ...) 移动到午夜,但是您可能会注意到我的示例point_in_time,该日期的午夜位于夏令时开关的另一侧!

结果是我得到了代表 UTC datetime(2017, 3, 12, 7) 的时间,而不是代表 UTC datetime(2017, 3, 12, 8) 的时间,这是真正的午夜。

编辑: 我实际上在想我的问题和相关问题之间的区别在于我正在寻找过去最近的午夜。这个问题的答案似乎可以给出一个午夜,也许是过去或未来?

【问题讨论】:

别忘了,并不是每个时区的每一天都有午夜。至少,如果您将午夜定义为00:00,则不会。例如,2016 年 10 月 16 日在America/Sao_Paulo 中,这一天从01:00 开始。 Reference here。这比你想象的更常见。世界各地的几个时区在午夜时分切换到 DST 弹簧向前间隙,因此从 23:59:59.999 变为 01:00:00.000 【参考方案1】:

您的示例突出了在本地时区进行日期时间算术的危险。

您可能可以使用 pytz 的 normalize() 函数来实现这一点,但这是我想到的方法:

point_in_time = datetime(2017, 3, 12, 16, tzinfo=pytz.utc)
pacific = pytz.timezone("US/Pacific")
pacific_time = point_in_time.astimezone(pacific)
pacific_midnight_naive = pacific_time.replace(hour=0, tzinfo=None)
pacific_midnight_aware = pacific.localize(pacific_midnight_naive)
pacific_midnight_aware.astimezone(pytz.utc)  # datetime(2017, 3, 12, 8)

换句话说,您首先转换为太平洋时间以找出正确的日期;然后从该日期的午夜再次转换以获得正确的本地时间。

【讨论】:

漂亮!实际上,我基本上得到了这个确切的答案(但使用 .date() 来摆脱时间/时区,就像使用 .replace() 一样)。关键是首先使用 .astimezone 获取日期,然后清除时区并重新本地化【参考方案2】:

"US/Pacific" 等命名时区根据定义是夏令时感知的。如果您希望使用相对于 GMT 的固定非夏令时感知偏移量,您可以使用时区 "Etc/GMT+*",其中 * 是所需的偏移量。例如,对于美国太平洋标准时间,您可以使用 "Etc/GMT+8"

import pandas as pd
point_in_time = pd.to_datetime('2017-03-12 16:00:00').tz_localize('UTC')

# not what you want
local_time = point_in_time.tz_convert("US/Pacific")
(local_time - pd.Timedelta(hours=local_time.hour)).tz_convert('UTC')
# Timestamp('2017-03-12 07:00:00+0000', tz='UTC')

# what you want
local_time = point_in_time.tz_convert("Etc/GMT+8")
(local_time - pd.Timedelta(hours=local_time.hour)).tz_convert('UTC')
# Timestamp('2017-03-12 08:00:00+0000', tz='UTC')

有关更多信息,请参阅http://pvlib-python.readthedocs.io/en/latest/timetimezones.html 的文档。

编辑现在我想一想,午夜 PST 将始终是世界标准时间上午 8 点,因此您可以将其简化为

if point_in_time.hour >=8:
    local_midnight = point_in_time - point_in_time.hour + 8
else:
    local_midnight = point_in_time - point_in_time.hour - 16

【讨论】:

不幸的是,即使有了这些信息,问题仍未解决:(。我确信有人以前做过一些令人讨厌的本地化和剥离时间组合(我目前正在处理弄清楚),但正如问题中所述,我使用的方法,即使使用命名时区,也会产生不正确的结果。 我认为我的答案应该对你有用,除非我误解了你的问题,我添加了一个例子来说明

以上是关于给定 UTC 时间,获取特定时区是午夜的主要内容,如果未能解决你的问题,请参考以下文章

在特定时区的一天开始时获取时间对象

使用 Joda-Time 获取给定日期和时区的 UTC 偏移量

给定 UTC 时间戳和 UTC 偏移量,是不是可以在 Python 中获取时区?

如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]

ruby 获取给定时区的时间

NSDate 比较,找出特定(本地)时区的“午夜数”