如何获取给定时区的 UTC“午夜”时间?

2025-02-21 08:50:00
admin
原创
6
摘要:问题描述:目前我能想到的最好的办法就是这个:>>> datetime.utcnow() \n... .replace(tzinfo=pytz.UTC) \n... .astimezone(pytz.timezone("Australia/Melbourne")) ...

问题描述:

目前我能想到的最好的办法就是这个:

>>> datetime.utcnow() \n...   .replace(tzinfo=pytz.UTC) \n...   .astimezone(pytz.timezone("Australia/Melbourne")) \n...   .replace(hour=0,minute=0,second=0,microsecond=0) \n...   .astimezone(pytz.UTC) \n...   .replace(tzinfo=None)
datetime.datetime(2008, 12, 16, 13, 0)

即,用英语获取当前时间(UTC),将其转换为其他时区,将时间设置为午夜,然后转换回UTC。

我不只是使用 now() 或 localtime(),因为它们会使用服务器的时区,而不是用户的时区。

我禁不住感到自己错过了一些东西,有什么想法吗?


解决方案 1:

我认为如果这样做的话,你可以减少一些方法调用:

>>> from datetime import datetime
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \n            .replace(hour=0, minute=0, second=0, microsecond=0) \n            .astimezone(pytz.utc)

但是......您的代码中存在一个比美学更大的问题:它会在夏令时切换当天给出错误的结果。

原因在于日期时间构造函数都没有replace()考虑 DST 变化。

例如:

>>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne"))
>>> print now
2012-04-01 05:00:00+10:00
>>> print now.replace(hour=0)
2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00
>>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz)
2012-03-01 00:00:00+10:00 # wrong again!

然而,文件指出tz.localize()

此方法应用于构造本地时间,而不是将 tzinfo 参数传递给 datetime 构造函数。

因此,您的问题可以这样解决:

>>> import pytz
>>> from datetime import datetime, date, time

>>> tz = pytz.timezone("Australia/Melbourne")
>>> the_date = date(2012, 4, 1) # use date.today() here

>>> midnight_without_tzinfo = datetime.combine(the_date, time())
>>> print midnight_without_tzinfo
2012-04-01 00:00:00

>>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo)
>>> print midnight_with_tzinfo
2012-04-01 00:00:00+11:00

>>> print midnight_with_tzinfo.astimezone(pytz.utc)
2012-03-31 13:00:00+00:00

但无法保证 1582 年之前的日期。

解决方案 2:

@hop 的答案在夏令时 (DST) 转换日(例如 2012 年 4 月 1 日)是错误的。要修复它tz.localize()可以使用:

tz = pytz.timezone("Australia/Melbourne")
today = datetime.now(tz).date()
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
utc_dt = midnight.astimezone(pytz.utc)        

评论也一样:

#!/usr/bin/env python
from datetime import datetime, time
import pytz # pip instal pytz

tz = pytz.timezone("Australia/Melbourne") # choose timezone

# 1. get correct date for the midnight using given timezone.
today = datetime.now(tz).date()

# 2. get midnight in the correct timezone (taking into account DST)
#NOTE: tzinfo=None and tz.localize()
# assert that there is no dst transition at midnight (`is_dst=None`)
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)

# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no 
#    DST transitions)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print midnight.astimezone(pytz.utc).strftime(fmt)

解决方案 3:

使用 dateutil.tz 比使用 pytz 更直接:

>>>import datetime
>>>import dateutil.tz
>>>midnight=(datetime.datetime
             .now(dateutil.tz.gettz('Australia/Melbourne'))
             .replace(hour=0, minute=0, second=0, microsecond=0)
             .astimezone(dateutil.tz.tzutc()))
>>>print(midnight)
2019-04-26 14:00:00+00:00

自 Python 3.6 起, tzinfo 文档推荐使用 dateutil.tz。dateutil.tz 中的 tzinfo 对象不会出现 DST 等异常问题,无需 pytz 的本地化功能。使用 user3850 的示例:

>>> now = (datetime.datetime(2012, 4, 1, 5,  
...         tzinfo = dateutil.tz.gettz('Australia/Melbourne'))) 
>>> print(now.replace(hour = 0).astimezone(dateutil.tz.tzutc()))
2012-03-31 13:00:00+00:00

解决方案 4:

设置 TZ 环境变量会修改 Python 的日期和时间函数所使用的时区。

>>> time.gmtime()
(2008, 12, 17, 1, 16, 46, 2, 352, 0)
>>> time.localtime()
(2008, 12, 16, 20, 16, 47, 1, 351, 0)
>>> os.environ['TZ']='Australia/Melbourne'
>>> time.localtime()
(2008, 12, 17, 12, 16, 53, 2, 352, 1)

解决方案 5:

每个时区都有一个数字,例如 US/Central = -6。这被定义为与 UTC 的小时偏移量。由于 0000 是午夜,因此您可以简单地使用此偏移量来查找 UTC 午夜时任何时区的时间。要访问该时间,我相信您可以使用

时间.时区

根据Python 文档,time.timezone 实际上给出了这个数字的负值:

时间.时区

当地(非 DST)时区的偏移量,以 UTC 以西的秒数表示(西欧大部分地区为负数,美国为正数,英国为零)。

因此,如果它是正数,则您只需使用该数字表示小时数(例如,如果是芝加哥的午夜(其时区值为 +6),那么它就是 6000 = UTC 时间早上 6 点)。

如果数字为负数,则从 24 中减去。例如,柏林会给出 -1,因此 24 - 1 => 2300 = 晚上 11 点。

解决方案 6:

值得注意的是,我们可以调整 @jfs 给出的答案来查找明天的午夜或昨天的午夜等。诀窍是将一定天数添加到感知时区。这是有效的,因为虽然这通常会增加 24 小时,但有时根据 DST 问题可能会增加 23 或 25 小时。

from datetime import datetime, time, timedelta
import pytz

def midnight_UTC(offset):

    # Construct a timezone object
    tz = pytz.timezone('Australia/Melbourne')

    # Work out today/now as a timezone-aware datetime
    today = datetime.now(tz)

    # Adjust by the offset. Note that that adding 1 day might actually move us 23 or 25
    # hours into the future, depending on daylight savings. This works because the {today}
    # variable is timezone aware
    target_day = today + timedelta(days=1) * offset

    # Discard hours, minutes, seconds and microseconds
    midnight_aware = tz.localize(
        datetime.combine(target_day, time(0, 0, 0, 0)), is_dst=None)

    # Convert to UTC
    midnight_UTC = midnight_aware.astimezone(pytz.utc)

    return midnight_UTC

print("The UTC time of the previous midnight is:", midnight_UTC(0))
print("The UTC time of the upcoming midnight is:", midnight_UTC(1))
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1267  
  IPD(Integrated Product Development)即集成产品开发,是一套先进的、成熟的产品开发管理理念、模式和方法。随着市场竞争的日益激烈,企业对于提升产品开发效率、降低成本、提高产品质量的需求愈发迫切,IPD 项目管理咨询市场也迎来了广阔的发展空间。深入探讨 IPD 项目管理咨询的市场需求与发展,...
IPD集成产品开发流程   27  
  IPD(Integrated Product Development)产品开发流程是一套先进的、被广泛应用的产品开发管理体系,它涵盖了从产品概念产生到产品推向市场并持续优化的全过程。通过将市场、研发、生产、销售等多个环节紧密整合,IPD旨在提高产品开发的效率、质量,降低成本,增强企业的市场竞争力。深入了解IPD产品开发...
IPD流程中TR   31  
  IPD(Integrated Product Development)测试流程是确保产品质量、提升研发效率的关键环节。它贯穿于产品从概念到上市的整个生命周期,对企业的成功至关重要。深入理解IPD测试流程的核心要点,有助于企业优化研发过程,打造更具竞争力的产品。以下将详细阐述IPD测试流程的三大核心要点。测试策略规划测试...
华为IPD   26  
  华为作为全球知名的科技企业,其成功背后的管理体系备受关注。IPD(集成产品开发)流程作为华为核心的产品开发管理模式,在创新管理与技术突破方面发挥了至关重要的作用。深入剖析华为 IPD 流程中的创新管理与技术突破,对于众多企业探索自身发展路径具有重要的借鉴意义。IPD 流程概述IPD 流程是一种先进的产品开发管理理念和方...
TR评审   26  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用