Python:如何根据当前UTC时间确定特定时区一天的开始和结束时间?

5 投票
5 回答
3772 浏览
提问于 2025-04-17 00:28

我在玩谷歌的应用引擎,发现它的时区是固定为UTC(协调世界时)。我想知道用户本地时间的今天开始和结束的时间。简单来说,就是在已知当前UTC时间的情况下,如何计算出今天的开始和结束时间,同时考虑到夏令时的变化。

我有一些不太优雅的示例代码。请注意,我知道如果我手动指定一个日期,我也可以指定明天的日期,但这些只是示例,我想通过编程来确定这些时间。我的主要问题是,如果我在一个带时区的日期时间上加上一个时间差,然后进行标准化(就像pytz文档中建议的那样),我会发现夏令时切换时得到的日期时间会差一个小时。

代码中没有提到,但最终的目标是将这些时间转换回UTC,这就是为什么了解时区非常重要。

#!/usr/bin/python

import datetime
from pytz.gae import pytz

hobart_tz = pytz.timezone('Australia/Hobart')

utc_dt = pytz.utc.localize(datetime.datetime.utcnow())
hobart_dt = utc_dt.astimezone(hobart_tz)

# create a new datetime for the start of the day and add a day to it to get tomorrow.
today_start = datetime.datetime(hobart_dt.year, hobart_dt.month, hobart_dt.day)
today_start = hobart_tz.localize(today_start)
today_end = hobart_tz.normalize(today_start + datetime.timedelta(days=1))
print 'today:', today_start
print ' next:', today_end
print
# gives:
# today: 2011-08-28 00:00:00+10:00
# next: 2011-08-29 00:00:00+10:00

# but say today is a daylight savings changeover.
# after normalisation, we are off by an hour.

dst_finish_2011 = datetime.datetime(2011, 4, 3)  # this would come from hobart_dt
dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
next = hobart_tz.normalize(dst_finish_2011 + datetime.timedelta(days=1))
print '2011-04-03:', dst_finish_2011
print '2011-04-04:', next   # expect 2011-04-04 00:00:00+10:00
print
# gives
# 2011-04-03: 2011-04-03 00:00:00+11:00
# 2011-04-04: 2011-04-03 23:00:00+10:00 (wrong)

dst_start_2011 = datetime.datetime(2011, 10, 2)  # this would come from hobart_dt
dst_start_2011 = hobart_tz.localize(dst_start_2011)
next = hobart_tz.normalize(dst_start_2011 + datetime.timedelta(days=1))
print '2011-10-02:', dst_start_2011
print '2011-10-03:', next   # expect 2011-10-03 00:00:00+11:00
print
# gives
# 2011-10-02: 2011-10-02 00:00:00+10:00
# 2011-10-03: 2011-10-03 01:00:00+11:00 (wrong)

# I guess we could ignore the timezone and localise *after* ?

dst_finish_2011 = datetime.datetime(2011, 4, 3)  # this would come from hobart_dt
next = dst_finish_2011 + datetime.timedelta(days=1)
# now localise
dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
next = hobart_tz.localize(next)
print '2011-04-03:', dst_finish_2011
print '2011-04-04:', next   # expect 2011-04-04 00:00:00+10:00
print
# gives
# 2011-04-03: 2011-04-03 00:00:00+11:00
# 2011-04-04: 2011-04-04 00:00:00+10:00

5 个回答

-1

下面的代码试图获取午夜的时间;如果因为时区调整导致失败,它会根据新的时区偏移量重新调整回午夜的时间。

def DayStartEnd(localized_dt):
    tz = localized_dt.tzinfo
    start = tz.normalize(datetime.datetime(localized_dt.year,localized_dt.month,localized_dt.day,0,0,0,0,tz))
    after_midnight = start.hour*60*60 + start.minute*60 + start.second
    if start.day != localized_dt.day:
        start += datetime.timedelta(seconds = 24*60*60 - after_midnight)
    elif after_midnight != 0:
        start -= datetime.timedelta(seconds = after_midnight)
    end = tz.normalize(start + datetime.timedelta(hours=24))
    after_midnight = end.hour*60*60 + end.minute*60 + end.second
    if end.day == localized_dt.day:
        end += datetime.timedelta(seconds = 24*60*60 - after_midnight)
    elif after_midnight != 0:
        end -= datetime.timedelta(seconds = after_midnight)
    return start,end

>>> hobart_tz = pytz.timezone('Australia/Hobart')
>>> dst_finish_2011 = datetime.datetime(2011, 4, 3)
>>> dst_finish_2011 = hobart_tz.localize(dst_finish_2011)
>>> start,end = DayStartEnd(dst_finish_2011)
>>> print start,end
2011-04-03 00:00:00+11:00 2011-04-04 00:00:00+10:00
>>> dst_start_2011 = datetime.datetime(2011, 10, 2)
>>> dst_start_2011 = hobart_tz.localize(dst_start_2011)
>>> start,end = DayStartEnd(dst_start_2011)
>>> print start,end
2011-10-02 00:00:00+10:00 2011-10-03 00:00:00+11:00
0

我觉得你得到这个结果是因为你在加一天,而不是加86400秒。其实,天和秒之间并没有一个总是正确的换算关系。举个例子,如果pytz强制规定一天就是86400秒,那么在12月31日或6月30日这一天加一天,有时候结果的秒数会“差一秒”,因为在某些年份,这些天的秒数实际上是86401秒。(将来这些天的秒数可能会变成86402秒,甚至86399秒。)

所以,加一天的意思就是简单地把日期加一,如果需要的话,月份和年份也会相应调整,但时间部分不会改变。你可以试试加86400秒,看看结果是否符合你的预期。

2

要在本地时区中找到一天的开始时间(午夜)和结束时间(明天),前提是你知道UTC时间:

#!/usr/bin/env python
from datetime import datetime, time, timedelta
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

tz = get_localzone() # get the local timezone as pytz.timezone
now = datetime.now(pytz.utc) # some UTC time
dt = now.astimezone(tz) # the same time in the local timezone
today = dt.date() # today in the local timezone (naive date object)
midnight = datetime.combine(today, time()) # midnight in the local timezone
aware_midnight = tz.localize(midnight, is_dst=None) # raise exception
                                                    # for ambiguous or
                                                    # non-existing
                                                    # times
tomorrow = midnight + timedelta(1)
aware_tomorrow = tz.localize(tomorrow, is_dst=None)

def print_time(aware_dt, fmt="%Y-%m-%d %H:%M:%S %Z%z"):
    print(aware_dt.strftime(fmt))
    utc_dt = aware_dt.astimezone(pytz.utc) # the same time in UTC
    print(utc_dt.strftime(fmt))

print_time(aware_midnight)
print_time(aware_tomorrow)

输出结果

2014-09-01 00:00:00 EST+1000
2014-08-31 14:00:00 UTC+0000
2014-09-02 00:00:00 EST+1000
2014-09-01 14:00:00 UTC+0000

另外,

撰写回答