关于python:’datetime.datetime’对象的属性’tzinfo’是不可写的

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

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

当它第一次出现时它是UTC。 我想把它改成EST。

我正在尝试,例如:

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

检索Book时,我想立即设置其tzinfo:

1
book.creationTime.tzinfo = EST

我将这个例子用于我的EST对象

但是我得到:

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

我已经看到了一些推荐pytz和python-dateutil的答案,但我真的想要回答这个问题。


datetime的对象是不可变的,因此您永远不会更改它们的任何属性 - 您创建一个具有相同属性和新属性的新对象,并将其分配给您需要分配给它的任何属性。

即,在你的情况下,而不是

1
book.creationTime.tzinfo = EST

你必须编码

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


如果您正在接收EST中的日期时间,但未设置其tzinfo字段,请使用dt.replace(tzinfo=tz)分配tzinfo而不修改时间。 (您的数据库应该为您执行此操作。)

如果您正在接收UDT中的日期时间,并且您希望它在EST中,那么您需要astimezone。http://docs.python.org/library/datetime.html#datetime.datetime.astimezone

在绝大多数情况下,您的数据库应该在UDT中存储和返回数据,您不需要使用replace(除了可能分配UDT tzinfo)。


你想要的就是文档中的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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

输出:

1
2
3
2010-01-18 17:08:02.741482
None
2010-01-18 17:08:02.741482-05:00