datetime.datetime'对象的'tzinfo'属性不可写

40 投票
3 回答
41956 浏览
提问于 2025-04-15 18:10

我该如何设置一个刚从数据库取出的日期时间实例的时区呢?

它一开始是以UTC时间显示的。我想把它改成东部标准时间(EST)。

我试着这样做,比如:

class Book( db.Model ):
    creationTime = db.DateTimeProperty()

当我获取一本书的时候,我想立刻设置它的时区信息:

book.creationTime.tzinfo = EST

在这里,我使用了这个示例来创建我的EST对象。

但是我得到了:

attribute 'tzinfo' of 'datetime.datetime' objects is not writable

我看到有很多答案推荐使用pytz和python-dateutil库,但我真的想要这个问题的答案。

3 个回答

0

你想要的内容就在这个文档里。

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)
DSTSTART = datetime(1, 4, 1, 2)
DSTEND = datetime(1, 10, 25, 1)

def first_sunday_on_or_after(dt):
    days_to_go = 6 - dt.weekday()
    if days_to_go:
        dt += timedelta(days_to_go)
    return dt

class USTimeZone(tzinfo):

    def __init__(self, hours, reprname, stdname, dstname):
        self.stdoffset = timedelta(hours=hours)
        self.reprname = reprname
        self.stdname = stdname
        self.dstname = dstname

    def __repr__(self):
        return self.reprname

    def tzname(self, dt):
        if self.dst(dt):
            return self.dstname
        else:
            return self.stdname

    def utcoffset(self, dt):
        return self.stdoffset + self.dst(dt)

    def dst(self, dt):
        if dt is None or dt.tzinfo is None:
            # An exception may be sensible here, in one or both cases.
            # It depends on how you want to treat them.  The default
            # fromutc() implementation (called by the default astimezone()
            # implementation) passes a datetime with dt.tzinfo is self.
            return ZERO
        assert dt.tzinfo is self

        # Find first Sunday in April & the last in October.
        start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
        end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))

        # Can't compare naive to aware objects, so strip the timezone from
        # dt first.
        if start <= dt.replace(tzinfo=None) < end:
            return HOUR
        else:
            return ZERO

now = datetime.now()
print now
print now.tzinfo

Eastern = USTimeZone(-5, 'Eastern', 'EST', 'EDT')
now_tz_aware = now.replace(tzinfo=Eastern)
print now_tz_aware

输出结果:

2010-01-18 17:08:02.741482
None
2010-01-18 17:08:02.741482-05:00
7

如果你收到的时间是东部标准时间(EST),但没有设置时区信息(tzinfo),你可以用 dt.replace(tzinfo=tz) 来给它加上时区信息,而不改变时间本身。(你的数据库应该帮你处理这个问题。)

如果你收到的时间是协调世界时(UDT),而你想把它转换成东部标准时间(EST),那么你需要使用 astimezone 方法。 http://docs.python.org/library/datetime.html#datetime.datetime.astimezone

在绝大多数情况下,你的数据库应该以协调世界时(UDT)来存储和返回数据,你通常不需要使用 replace 方法(除了可能需要给 UDT 加上时区信息)。

67

datetime对象是不可变的,这意味着你不能直接改变它们的属性。相反,你需要创建一个新的对象,这个新对象有些属性和原来的对象相同,有些则不同,然后把这个新对象赋值给你需要的地方。

也就是说,在你的情况下,不是这样写:

book.creationTime.tzinfo = EST

你需要这样写:

book.creationTime = book.creationTime.replace(tzinfo=EST)

撰写回答