关于datetime:使用时区Python打印正确的时间

Printing correct time using timezones, Python

扩展

好的,我们今天没有过好日子。

当您将正确的tzinfo对象附加到日期时间实例,然后strftime()它,它仍然以UTC格式出现,似乎忽略了我附加到它的漂亮的tzinfo对象。

1
2
3
4
5
6
    # python 2.5.4
    now = datetime.now()
    print now.strftime("%a %b %d %X" ) # %X is"locale's appropriate time rep"

    pst = now.replace( tzinfo=Pacific )
    print pst.strftime("%a %b %d %X" )

我们得到:

1
2
Mon Jan 18 17:30:16
Mon Jan 18 17:30:16

我发现如果我添加%z,我可以添加它应该计算的差异:

1
2
Mon Jan 18 17:32:38
Mon Jan 18 17:32:38 -0800

它只是在那里加-8,好像在说,"你自己做,foo。"

但是我希望strftime()能够简单地给我一个具有预定时间的字符串。

当我strftime()时,如何让strftime()为我做小时减法数学呢?

我正在使用的完整代码如下。

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)

# A UTC class.

class UTC(tzinfo):
 """UTC"""
  def utcoffset(self, dt):
    return ZERO
  def tzname(self, dt):
    return"UTC"
  def dst(self, dt):
    return ZERO

utc = UTC()

# A class building tzinfo objects for fixed-offset time zones.
# Note that FixedOffset(0,"UTC") is a different way to build a
# UTC tzinfo object.
class FixedOffset(tzinfo):
 """Fixed offset in minutes east from UTC."""

  def __init__(self, offset, name):
    self.__offset = timedelta(minutes = offset)
    self.__name = name

  def utcoffset(self, dt):
    return self.__offset

  def tzname(self, dt):
    return self.__name

  def dst(self, dt):
    return ZERO

# A class capturing the platform's idea of local time.

import time as _time

STDOFFSET = timedelta(seconds = -_time.timezone)
if _time.daylight:
  DSTOFFSET = timedelta(seconds = -_time.altzone)
else:
  DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):
  def utcoffset(self, dt):
    if self._isdst(dt):
      return DSTOFFSET
    else:
      return STDOFFSET

  def dst(self, dt):
    if self._isdst(dt):
      return DSTDIFF
    else:
      return ZERO

  def tzname(self, dt):
    return _time.tzname[self._isdst(dt)]

  def _isdst(self, dt):
    tt = (dt.year, dt.month, dt.day,
          dt.hour, dt.minute, dt.second,
          dt.weekday(), 0, -1)
    stamp = _time.mktime(tt)
    tt = _time.localtime(stamp)
    return tt.tm_isdst > 0

Local = LocalTimezone()


# A complete implementation of current DST rules for major US time zones.

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

# In the US, DST starts at 2am (standard time) on the first Sunday in April.
DSTSTART = datetime(1, 4, 1, 2)
# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
# which is the first Sunday on or after Oct 25.
DSTEND = datetime(1, 10, 25, 1)

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

Eastern  = USTimeZone(-5,"Eastern", "EST","EDT")
#Central  = USTimeZone(-6,"Central", "CST","CDT")
#Mountain = USTimeZone(-7,"Mountain","MST","MDT")
Pacific = USTimeZone(-8,"Pacific", "PST","PDT")

now = datetime.now()
print now.strftime("%a %b %d %X %z" )

pst = now.replace( tzinfo=Pacific )
print pst.strftime("%a %b %d %X %z" )


.replace不进行计算:它只是替换新返回对象中的一个或多个字段,同时从调用它的对象中复制所有其他字段。

如果我正确理解你的情况,你可以从一个日期时间对象开始,你知道(通过其他方式)是UTC,但不知道它本身(具有None的tzinfo属性,意思是"我完全无能为力"我所在的时区。

因此,首先,您从输入的时区初始对象中获取时区感知,以便通知它它是时区UTC(所有其他字段都被复制):

1
aware = naive.replace(tzinfo=utc)

然后,您可以请求有关时区的计算,然后打印:

1
print aware.astimezone(Pacific).strftime('%a %b %d %X %z')

使用dt.replace(tzinfo=tz)你并没有真正转换时间值,你只是说'嘿不,等等,这次实际上是在PDT中,而不是在UTC中'。您可能希望使用datetime.astimezone(tz)


我认为Wim有正确的想法,只是倒退。如果您想知道UTC时间,请使用:

1
print pst.astimezone(UTC).strftime("%a %b %d %X" )

您必须挖掘UTC时区类的定义。我理解为什么Python不想提供每个可能的tzinfo的默认实现,但UTC应该包含在基础包中。