我现在能想到的最好的就是这种怪异:
>>> datetime.utcnow() \
... .replace(tzinfo=pytz.UTC) \
... .astimezone(pytz.timezone("Australia/Melbourne")) \
... .replace(hour=0,minute=0,second=0,microsecond=0) \
... .astimezone(pytz.UTC) \
... .replace(tzinfo=None)
datetime.datetime(2008, 12, 16, 13, 0)
即,用英语,获取当前时间(以UTC为单位),将其转换为其他时区,将时间设置为午夜,然后转换回UTC。
我不只是使用now()或localtime(),因为它会使用服务器的时区,而不是用户的时区。
我不禁感到我错过了什么,有什么想法吗?
答案 0 :(得分:57)
如果您这样做,我认为您可以减少一些方法调用:
>>> from datetime import datetime
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \
.replace(hour=0, minute=0, second=0, microsecond=0) \
.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年之前的日期。
答案 1 :(得分:24)
@hop's answer错误。要解决此问题,可以使用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)
答案 2 :(得分:0)
设置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)
答案 3 :(得分:0)
每个时区都有一个数字,例如US / Central = -6。这被定义为UTC的小时偏移量。由于0000是午夜,您只需使用此偏移量即可在午夜UTC时间内查找任何时区的时间。要访问它,我相信您可以使用
time.timezone
根据The Python Docs,time.timezone实际上给出了这个数字的负值:
time.timezone
本地(非DST)时区的偏移量,以UTC为单位的西秒(西欧大部分地区为负,美国为零,英国为零)。
所以如果它是正数的话,你只需要用这个数字表示时间(例如,如果它是在芝加哥的午夜(具有+6时区值),那么它是6000 = UTC时间早上6点。)
如果数字为负数,则从24减去。例如,柏林将给出-1,因此24 - 1 => 2300 =晚上11点。
答案 4 :(得分:0)
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
tzinfo documentation从Python 3.6开始推荐dateutil.tz。 dateutil.tz中的tzinfo对象无需使用pytz的本地化功能即可解决DST等异常问题。使用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
答案 5 :(得分:0)
值得一提的是,我们可以使用@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))