pytz和astimezone()不能应用于一个无时区的日期时间。

58

我有一个日期,需要将其转换为时区感知的时间。

local_tz = timezone('Asia/Tokyo')
start_date = '2012-09-27'
start_date = datetime.strptime(start_date, "%Y-%m-%d")   
start_date = start_date.astimezone(local_tz)


now_utc = datetime.now(timezone('UTC'))
local_now = now_utc.astimezone(local_tz)

我需要判断这是否为真:

print start_date>local_now

但我收到了这个错误。

   start_date = start_date.astimezone(local_tz)
   ValueError: astimezone() cannot be applied to a naive datetime

我成功地将UTC转换为东京时间。我需要让start_date也在东京成为时区感知。

谢谢


4
自 Python 3.6 版本起,astimezone 可以处理不带时区信息的日期时间。如果你还在使用低版本(<=3.5),则需要调用 pytz.localize() 来为不带时区信息的日期时间添加时区信息。 - Lyle
3个回答

60

对于 pytz 时区, 使用它们的 .localize() 方法将一个 naive 的 datetime 对象转换为带有时区信息的对象:

start_date = local_tz.localize(start_date)

对于没有夏令时变化的时区,使用.replace() 方法 将时区附加到一个naive的datetime对象通常也可以正常工作:

start_date = start_date.replace(tzinfo=local_tz)

查看 pytz 文档的本地化时间和日期算术以获取更多细节。


10
根据pytz文档,直接使用tzinfo属性来设置时区会在许多时区上失败。应该使用tz.localize()代替。 - jfs
@J.F.Sebastian,如果你想看一个糟糕的例子,可以看看https://dev59.com/ZWgu5IYBdhLWcg3wRlL0,注意这与夏令时无关。 - Mark Ransom
@J.F.Sebastian:有趣。已更新答案。 - Martijn Pieters
@MarkRansom:我知道。pytz使用“Europe/Amsterdam”作为示例。 - jfs
Python又来了一个WTF! - Kevin Parker
对于任何具有非固定UTC偏移量的local_tz(无论出于什么原因,而不仅仅是夏令时,例如,Europe/Moscow最近更改了UTC偏移量),start_date.replace(tzinfo=local_tz)都是错误的。@Kevin:你知道Python或任何语言中更好的datetime/timezone API吗?(认真问题:当我研究这个问题时,我的结论是:“时区很复杂”。你的代码可能也很复杂或者简单而错误(许多人不介意计算机不能告诉正确的时间)。tz数据库(由pytz提供)是复杂性和正确性之间的良好折衷方案)。 - jfs

17
你可以使用 local_tz.localize(naive_dt, is_dst=None) 来将一个本地时间对象转换为带时区的时间对象。
from datetime import datetime
import pytz

local_tz = pytz.timezone('Asia/Tokyo')

start_date = local_tz.localize(datetime(2012, 9, 27), is_dst=None)
now_utc = datetime.utcnow().replace(tzinfo=pytz.utc)

print start_date > now_utc

is_dst=None 强制 .localize() 在给定的本地时间存在歧义时引发异常。


1
如果您正在使用Django Rest Framework,您可以像这样覆盖DateTimeField类:
class DateTimeFieldOverridden(serializers.DateTimeField):

def to_representation(self, value):
    local_tz = pytz.timezone(TIME_ZONE)
    value = local_tz.localize(value)
    return super(DateTimeFieldOverridden, self).to_representation(value)

在序列化器中,您可以像这样使用它:
date_time = DateTimeFieldOverridden(format='%d-%b-%Y', read_only=True)

希望这能帮助到某人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接