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

39

我如何设置刚从数据存储中获取的日期时间实例的时区?

当它第一次出现时,它在UTC时区。 我想将其更改为东部标准时间(EST)。

例如,我尝试:

class Book( db.Model ):
    creationTime = db.DateTimeProperty()
当检索到一本书时,我希望立即设置它的tzinfo。
book.creationTime.tzinfo = EST

我想在我的EST对象中使用这个例子,但是我得到了以下错误:

datetime.datetime对象的属性“tzinfo”不可写。

我看到许多答案都推荐使用pytz和python-dateutil,但我真的想得到这个问题的答案。

3个回答

65

datetime 对象是不可变的,所以您永远不会更改它们的任何属性 -- 您将创建一个新的对象,其中一些属性相同,一些属性不同,并将其分配给您需要分配的任何内容。

也就是说,在您的情况下,而不是

book.creationTime.tzinfo = EST

你必须编写代码

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

2
注意:它不会将UTC转换为EST时区(“它首先是在UTC中。我想将其更改为EST。”)。时间保持不变。要进行转换,可以使用book.creationTime.astimezone(EST) - jfs

7
如果您收到一个在东部标准时间(EST)的日期时间,但没有设置其tzinfo字段,则可以使用“dt.replace(tzinfo=tz)”进行赋值,而不会修改时间。 (您的数据库应该为您执行此操作。)
如果您收到的日期时间在UDT中,并且希望将其转换为EST,则需要使用astimezone。请查看http://docs.python.org/library/datetime.html#datetime.datetime.astimezone 在绝大多数情况下,您的数据库应该存储和返回UDT数据,因此您不需要使用replace(除非可能需要分配UDT tzinfo)。

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

3
这并不是非常信息化的。你可以通过说使用datetime.replace(tzinfo=...)来解释同样的内容,但你没有解释他应该如何获取他想要的时区信息,而是硬编码了一个EST/EDT时区。 - Auspex

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