datetime.tzinfo基本日期和时间类型的tzinfo对象详解(24)Python语言(必读进阶学习教程)(参考资料)
- 类
datetime.
tzinfo
- 这是一个抽象基类,这意味着不应该直接实例化此类。您需要派生一个具体的子类,并且(至少)提供您使用的
tzinfo
方法所需的标准方法的 实现datetime
。该datetime
模块提供的一个简单的具体子类tzinfo
,timezone
,其可以代表与从UTC固定偏移,如UTC本身或北美EST和EDT时区。(的具体子类)的实例
tzinfo
可以传递给构造函数datetime
和time
对象。后一个对象将其属性视为在本地时间,并且该tzinfo
对象支持显示本地时间与UTC的偏移量,时区名称和DST偏移量的方法,所有这些都是相对于传递给它们的日期或时间对象。酸洗的特殊要求:
tzinfo
子类必须有一个__init__()
可以在没有参数的情况下调用的 方法,否则它可以被腌制但可能不再被打开。这是一项可能在将来放松的技术要求。具体的子类
tzinfo
可能需要实现以下方法。究竟需要哪些方法取决于对知识datetime
对象的使用 。如果有疑问,只需实施所有这些。
tzinfo.
utcoffset
(dt )- 返回当地时间与UTC的偏移量,作为UTC
timedelta
正东方的对象。如果当地时间在UTC以西,那么这应该是负数。请注意,这是UTC的总偏移量; 例如,如果tzinfo
对象同时表示时区和DST调整,utcoffset()
则应返回其总和。如果未知UTC偏移量,则返回None
。否则返回的值必须是timedelta
严格介于-timedelta(hours=24)
和 之间的 对象timedelta(hours=24)
(偏移的大小必须小于一天)。大多数实现utcoffset()
可能看起来像这两个中的一个:return CONSTANT # fixed-offset class return CONSTANT + self.dst(dt) # daylight-aware class
如果
utcoffset()
不退货None
,dst()
也不应退货None
。utcoffset()
加注 的默认实现NotImplementedError
。版本3.7中已更改: UTC偏移量不限于整数分钟。
tzinfo.
dst
(dt )- 返回夏令时(DST)调整,作为
timedelta
对象或None
未知DST信息。timedelta(0)
如果夏令时没有生效,则返回。如果DST有效,则将偏移量作为timedelta
对象返回(utcoffset()
有关详细信息,请参阅参考资料)。请注意,如果适用,DST偏移量已添加到返回的UTC偏移量中utcoffset()
,因此dst()
除非您有兴趣单独获取DST信息,否则无需咨询。例如,datetime.timetuple()
调用其tzinfo
属性的dst()
方法来确定tm_isdst
应如何设置标志,并在跨越时区时tzinfo.fromutc()
调用dst()
帐户以更改DST。在这个意义上,模拟标准时间和日光时间的子类的实例tz
tzinfo
必须是一致的:tz.utcoffset(dt) - tz.dst(dt)
必须返回相同的结果为每DT与 对于健全的子类,这个表达式产生的时区的“标准偏差”,它不应该依赖于日期或时间,但仅限于地理位置。执行 依赖于此,但无法检测违规行为; 程序员有责任确保它。如果子类不能保证这一点,它可能能够覆盖默认实现, 无论如何都能正常工作。
datetime
dt.tzinfo ==tz
tzinfo
datetime.astimezone()
tzinfo
tzinfo.fromutc()
astimezone()
大多数实现
dst()
可能看起来像这两个中的一个:def dst(self, dt): # a fixed-offset class: doesn't account for DST return timedelta(0)
要么
def dst(self, dt): # Code to set dston and dstoff to the time zone's DST # transition times based on the input dt.year, and expressed # in standard local time. Then if dston <= dt.replace(tzinfo=None) < dstoff: return timedelta(hours=1) else: return timedelta(0)
dst()
加注的默认实现NotImplementedError
。在版本3.7中更改: DST偏移不限于整数分钟。
tzinfo.
tzname
(dt )- 返回与
datetime
对象dt对应的时区名称,作为字符串。datetime
模块没有定义任何关于字符串名称的内容,也没有要求它特别指出任何内容。例如,“GMT”,“UTC”,“ – 500”,“ – 5:00”,“EDT”,“美国/东方”,“美国/纽约”都是有效的回复。None
如果字符串名称未知,则返回。请注意,这是一个方法而不是固定字符串,主要是因为某些tzinfo
子类希望根据传递的dt的特定值返回不同的名称,尤其是在tzinfo
类占日光时间的情况下。tzname()
加注的默认实现NotImplementedError
。
这些方法由a datetime
或time
object调用,以响应它们的相同名称的方法。甲datetime
对象本身传递作为参数,以及time
对象传递None
作为参数。一个tzinfo
因此子类的方法应该准备接受DT的说法None
,或一类datetime
。
如果None
获得通过,它是由类的设计者来决定最好的回应。例如,None
如果类希望说时间对象不参与tzinfo
协议,则返回是合适的。utcoffset(None)
返回标准UTC偏移量可能更有用,因为没有其他惯例可用于发现标准偏移量。
当datetime
响应datetime
方法传递对象时,dt.tzinfo
该对象与self相同。 tzinfo
除非用户代码tzinfo
直接调用方法,否则方法可以依赖于此。目的是该tzinfo
方法将dt解释为在本地时间,而不需要担心其他时区中的对象。
还有tzinfo
一个子类可能希望覆盖的方法:
tzinfo.
fromutc
(dt )- 这是从默认
datetime.astimezone()
实现中调用的。当从那里调用时,dt.tzinfo
是self,并且dt的日期和时间数据被视为表示UTC时间。目的fromutc()
是调整日期和时间数据,在自己的当地时间返回一个等效的日期时间。大多数
tzinfo
子类应该能够fromutc()
毫无问题地继承默认 实现。它足够强大,可以处理固定偏移时区,时区可以计算标准时间和日光时间,后者即使DST转换时间在不同年份也不同。fromutc()
在所有情况下,默认实现可能无法正确处理的时区的示例是标准偏移(来自UTC)取决于特定日期和时间的时区,这可能由于政治原因而发生。如果结果是跨越标准偏移量变化的时间之一,则默认实现astimezone()
并且fromutc()
可能不会产生您想要的结果。跳过错误情况的代码,默认
fromutc
()
实现如下:def fromutc(self, dt): # raise ValueError error if dt.tzinfo is not self dtoff = dt.utcoffset() dtdst = dt.dst() # raise ValueError if dtoff is None or dtdst is None delta = dtoff - dtdst # this is self's standard offset if delta: dt += delta # convert to standard local time dtdst = dt.dst() # raise ValueError if dtdst is None if dtdst: return dt + dtdst else: return dt
在以下tzinfo_examples.py
文件中有一些tzinfo
类的示例 :
from datetime import tzinfo, timedelta, datetime
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
SECOND = timedelta(seconds=1)
# A class capturing the platform's idea of local time.
# (May result in wrong values on historical times in
# timezones where UTC offset and/or the DST rules had
# changed in the past.)
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 fromutc(self, dt):
assert dt.tzinfo is
self stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND
args = _time.localtime(stamp)[:6]
dst_diff = DSTDIFF // SECOND
# Detect fold
fold = (args == _time.localtime(stamp - dst_diff))
return datetime(*args, microsecond=dt.microsecond, tzinfo=self, fold=fold)
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, 0)
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
# US DST Rules
#
# This is a simplified (i.e., wrong for a few cases) set of rules for US
# DST start and end times. For a complete and up-to-date set of DST rules
# and timezone definitions, visit the Olson Database (or try pytz):
# http://www.twinsun.com/tz/tz-link.htm # http://sourceforge.net/projects/pytz/ (might not be up-to-date)
#
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1, 3, 8, 2)
# and ends at 2am (DST time) on the first Sunday of Nov.
DSTEND_2007 = datetime(1, 11, 1, 2)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
# Sunday in April and to end at 2am (DST time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
DSTEND_1987_2006 = datetime(1, 10, 25, 2)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
# Sunday in April (the one on or after April 24) and to end at 2am (DST time)
# on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006
def us_dst_range(year):
# Find start and end times for US DST. For years before 1967, return
# start = end for no DST.
if 2006 < year:
dststart, dstend = DSTSTART_2007, DSTEND_2007
elif 1986 < year < 2007:
dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
elif 1966 < year < 1987:
dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
else:
return (datetime(year, 1, 1), ) * 2
start = first_sunday_on_or_after(dststart.replace(year=year))
end = first_sunday_on_or_after(dstend.replace(year=year))
return start, end
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
start, end = us_dst_range(dt.year)
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
dt = dt.replace(tzinfo=None)
if start + HOUR <= dt < end - HOUR:
# DST is in effect.
return HOUR
if end - HOUR <= dt < end:
# Fold (an ambiguous hour): use dt.fold to disambiguate.
return ZERO if dt.fold else HOUR
if start <= dt < start + HOUR:
# Gap (a non-existent hour): reverse the fold rule.
return HOUR if dt.fold else ZERO
# DST is off.
return ZERO
def fromutc(self, dt):
assert dt.tzinfo is self
start, end = us_dst_range(dt.year)
start = start.replace(tzinfo=self)
end = end.replace(tzinfo=self)
std_time = dt + self.stdoffset
dst_time = std_time + HOUR
if end <= dst_time < end + HOUR:
# Repeated hour
return std_time.replace(fold=1)
if std_time < start or dst_time >= end:
# Standard time
return std_time
if start <= std_time < end - HOUR:
# Daylight saving time
return dst_time
Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
Central = USTimeZone(-6, "Central", "CST", "CDT")
Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
Pacific = USTimeZone(-8, "Pacific", "PST", "PDT")
请注意tzinfo
,在DST过渡点,在标准和日光时间的子类中,每年有两次不可避免的微妙之处。具体情况,请考虑美国东部航空(UTC -0500),其中EDT在3月的第二个星期日1:59(美国东部时间)后的一分钟开始,并在11月的第一个星期日1:59(美国东部时间)结束时分钟:
UTC 3:MM 4:MM 5:MM 6:MM 7:MM 8:MM
EST 22:MM 23:MM 0:MM 1:MM 2:MM 3:MM
EDT 23:MM 0:MM 1:MM 2:MM 3:MM 4:MM
start 22:MM 23:MM 0:MM 1:MM 3:MM 4:MM
end 23:MM 0:MM 1:MM 1:MM 2:MM 3:MM
当DST开始时(“开始”行),本地挂钟从1:59跳到3:00。表格2:MM的挂号时间在当天没有任何意义,因此 在DST开始的那天astimezone(Eastern)
不会提供结果。例如,在2016年的春季前进过渡期,我们得到了hour == 2
>>> from datetime import datetime, timezone
>>> from tzinfo_examples import HOUR, Eastern
>>> u0 = datetime(2016, 3, 13, 5, tzinfo=timezone.utc)
>>> for i in range(4):
... u = u0 + i*HOUR
... t = u.astimezone(Eastern)
... print(u.time(), 'UTC =', t.time(), t.tzname())
...
05:00:00 UTC = 00:00:00 EST
06:00:00 UTC = 01:00:00 EST
07:00:00 UTC = 03:00:00 EDT
08:00:00 UTC = 04:00:00 EDT
当DST结束时(“结束”行),可能会出现更糟糕的问题:在当地的墙上时间内,有一个小时无法明确拼写:白天的最后一小时。在东部,日间时间结束时的形式为5:MM UTC的时间。当地挂钟从1:59(白天时间)再次跳回到1:00(标准时间)。形式1:MM的当地时间不明确。 astimezone()
通过将两个相邻的UTC小时映射到相同的本地小时,模仿本地时钟的行为。在东部示例中,形式为5:MM和6:MM的UTC时间在转换为Eastern时映射为1:MM,但较早时间将fold
属性设置为0,稍后将其设置为1。例如,在2016年的秋季过渡期,我们得到了
>>> u0 = datetime(2016, 11, 6, 4, tzinfo=timezone.utc)
>>> for i in range(4):
... u = u0 + i*HOUR
... t = u.astimezone(Eastern)
... print(u.time(), 'UTC =', t.time(), t.tzname(), t.fold)
...
04:00:00 UTC = 00:00:00 EDT 0
05:00:00 UTC = 01:00:00 EDT 0
06:00:00 UTC = 01:00:00 EST 1
07:00:00 UTC = 02:00:00 EST 0
请注意,在比较中datetime
,仅由fold
属性值不同的实例 被视为相等。
不能承受壁挂时间歧义的应用程序应该明确检查fold
属性的值或避免使用混合 tzinfo
子类; 使用时没有歧义timezone
,或任何其他固定偏移tzinfo
子类(例如仅代表EST(固定偏移-5小时)的类,或仅EDT(固定偏移-4小时))。
也可以看看
- dateutil.tz
-
标准库具有
timezone
用于处理来自UTC的任意固定偏移和timezone.utc
UTC时区实例的类。dateutil.tz库将IANA时区数据库(也称为Olson数据库)引入Python,建议使用它。
- IANA时区数据库
- 时区数据库(通常称为tz,tzdata或zoneinfo)包含代表全球许多代表性地点的当地时间历史的代码和数据。它会定期更新,以反映政治机构对时区边界,UTC偏移和夏令时规则所做的更改。