date
用法示例
计算距离特定事件天数的例子:
- >>> import time
- >>> from datetime import date
- >>> today = date.today()
- >>> today
- datetime.date(2007, 12, 5)
- >>> today == date.fromtimestamp(time.time())
- True
- >>> my_birthday = date(today.year, 6, 24)
- >>> if my_birthday < today:
- ... my_birthday = my_birthday.replace(year=today.year + 1)
- ...
- >>> my_birthday
- datetime.date(2008, 6, 24)
- >>> time_to_birthday = abs(my_birthday - today)
- >>> time_to_birthday.days
- 202
使用 date
的更多例子:
- >>> from datetime import date
- >>> d = date.fromordinal(730920) # 1. 1. 0001 之后第 730920 天
- >>> d
- datetime.date(2002, 3, 11)
- >>> # 有关格式化字符串输出的方法
- >>> d.isoformat()
- '2002-03-11'
- >>> d.strftime("%d/%m/%y")
- '11/03/02'
- >>> d.strftime("%A %d. %B %Y")
- 'Monday 11. March 2002'
- >>> d.ctime()
- 'Mon Mar 11 00:00:00 2002'
- >>> 'The {1} is {0:%d}, the {2} is {0:%B}.'.format(d, "day", "month")
- 'The day is 11, the month is March.'
- >>> # 用于在不同日历下提取‘部分’的方法
- >>> t = d.timetuple()
- >>> for i in t:
- ... print(i)
- 2002 # 年
- 3 # 月
- 11 # 日
- 0
- 0
- 0
- 0 # 星期序号 (0 = 星期一)
- 70 # 当年第 70 天
- -1
- >>> ic = d.isocalendar()
- >>> for i in ic:
- ... print(i)
- 2002 # ISO 年份
- 11 # ISO 年内周序号
- 1 # ISO 星期序号 ( 1 = 星期一 )
- >>> # 日期对象是不可变的;任何操作都将产生一个新对象
- >>> d.replace(year=2005)
- datetime.date(2005, 3, 11)
datetime
对象
datetime
对象是包含来自 date
对象和 time
对象的所有信息的单一对象。
与 date
对象一样,datetime
假定当前的格列高利历向前后两个方向无限延伸;与 time
对象一样,datetime
假定每一天恰好有 3600*24 秒。
构造器 :
- class datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)
year, month 和 day 参数是必须的。 tzinfo 可以是
None
或者是一个tzinfo
子类的实例。 其余的参数必须是在下面范围内的整数:MINYEAR <= year <= MAXYEAR
,1 <= month <= 12
,1 <= day <= 指定年月的天数
,0 <= hour < 24
,0 <= minute < 60
,0 <= second < 60
,0 <= microsecond < 1000000
,fold in [0, 1]
.
如果参数不在这些范围内,则抛出 ValueError
异常。
在 3.6 版本发生变更: 增加了 fold 形参。
其它构造器,所有的类方法:
- classmethod datetime.today()
- 返回表示当前地方时的 date 和 time,其中
tzinfo
为None
。
等价于:
- datetime.fromtimestamp(time.time())
另请参阅 now()
, fromtimestamp()
。
此方法的功能等价于 now()
,但是不带 tz
形参。
- classmethod datetime.now(tz=None)
- 返回表示当前地方时的 date 和 time 对象。
如果可选参数 tz 为 None
或未指定,这就类似于 today()
,但该方法会在可能的情况下提供比通过 time.time()
时间戳所获时间值更高的精度(例如,在提供了 C gettimeofday()
函数的平台上就可以做到这一点)。
如果 tz 不为 None
,它必须是 tzinfo
子类的一个实例,并且当前日期和时间将被转换到 tz 时区。
备注
对 datetime.now()
的后续调用可能由于下层时钟的精度返回相同的时刻。
- classmethod datetime.utcnow()
- 返回表示当前 UTC 时间的 date 和 time,其中
tzinfo
为None
。
这类似于 now()
,但返回的是当前 UTC 日期和时间,类型为简单型 datetime
对象。 感知型的当前 UTC 日期时间可通过调用 datetime.now(timezone.utc)
来获得。 另请参阅 now()
。
警告
由于简单型 datetime
对象会被许多 datetime
方法当作本地时间来处理,最好是使用感知型日期时间对象来表示 UTC 时间。 因此,创建表示当前 UTC 时间的对象的推荐方式是通过调用 datetime.now(timezone.utc)
。
自 3.12 版本弃用: 改用带 UTC
的 datetime.now()
。
- classmethod datetime.fromtimestamp(timestamp, tz=None)
- 返回 POSIX 时间戳对应的本地日期和时间,如
time.time()
返回的。 如果可选参数 tz 指定为None
或未指定,时间戳将转换为平台的本地日期和时间,并且返回的datetime
对象将为简单型。
如果 tz 不为 None
,它必须是 tzinfo
子类的一个实例,并且时间戳将被转换到 tz 指定的时区。
fromtimestamp()
可能会引发 OverflowError
,如果时间戳数值超出所在平台 C localtime()
或 gmtime()
函数的支持范围的话,并会在 localtime()
或 gmtime()
报错时引发 OSError
。 通常该数值会被限制在 1970 年至 2038 年之间。 请注意在时间戳概念包含闰秒的非 POSIX 系统上,闰秒会被 fromtimestamp()
所忽略,结果可能导致两个相差一秒的时间戳产生相同的 datetime
对象。 相比 utcfromtimestamp()
更推荐使用此方法。
在 3.3 版本发生变更: 引发 OverflowError
而不是 ValueError
,如果时间戳数值超出所在平台 C localtime()
或 gmtime()
函数的支持范围的话。 并会在 localtime()
或 gmtime()
出错时引发 OSError
而不是 ValueError
。
在 3.6 版本发生变更: fromtimestamp()
可能返回 fold
值设为 1 的实例。
- classmethod datetime.utcfromtimestamp(timestamp)
- 返回对应于 POSIX 时间戳的 UTC
datetime
,其中tzinfo
值为None
。 (结果为简单型对象。)
这可能引发 OverflowError
,如果时间戳数值超出所在平台 C gmtime()
函数的支持范围的话,并会在 gmtime()
报错时引发 OSError
。 通常该数值会被限制在 1970 至 2038 年之间。
要得到一个感知型 datetime
对象,应调用 fromtimestamp()
:
- datetime.fromtimestamp(timestamp, timezone.utc)
在 POSIX 兼容的平台上,它等价于以下表达式:
- datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp)
不同之处在于后一种形式总是支持完整年份范围:从 MINYEAR
到 MAXYEAR
的开区间。
警告
由于简单型 datetime
对象会被许多 datetime
方法当作本地时间来处理,最好是使用感知型日期时间对象来表示 UTC 时间。 因此,创建表示特定 UTC 时间戳的日期时间对象的推荐方式是通过调用 datetime.fromtimestamp(timestamp, tz=timezone.utc)
。
在 3.3 版本发生变更: 引发 OverflowError
而不是 ValueError
,如果时间戳数值超出所在平台 C gmtime()
函数的支持范围的话。 并会在 gmtime()
出错时引发 OSError
而不是 ValueError
。
自 3.12 版本弃用: 改用带 UTC
的 datetime.fromtimestamp()
。
- classmethod datetime.fromordinal(ordinal)
- 返回对应于预期格列高利历序号的
datetime
,其中公元 1 年 1 月 1 日的序号为 1。 除非1 <= ordinal <= datetime.max.toordinal()
否则会引发ValueError
。 结果的 hour, minute, second 和 microsecond 值均为 0,并且tzinfo
值为None
。
- classmethod datetime.combine(date, time, tzinfo=time.tzinfo)
- 返回一个新的
datetime
对象,其日期部分等于给定的date
对象的值,而其时间部分等于给定的time
对象的值。 如果提供了 tzinfo 参数,其值会被用来设置结果的tzinfo
属性,否则将使用 time 参数的tzinfo
属性。 如果 date 参数是一个datetime
对象,则其时间部分和tzinfo
属性将被忽略。
对于任意 datetime
对象 d
,d == datetime.combine(d.date(), d.time(), d.tzinfo)
。
在 3.6 版本发生变更: 增加了 tzinfo 参数。
- classmethod datetime.fromisoformat(date_string)
- 返回一个对应于以任何有效的 8601 格式给出的 date_string 的
datetime
,下列格式除外:
时区时差可能会有带小数的秒值。
T
分隔符可以用任何单个 unicode 字符来替换。带小数的时和分是不受支持的。
目前不支持降低精度的日期 (
YYYY-MM
,YYYY
)。目前不支持扩展日期表示形式 (
±YYYYYY-MM-DD
)。目前不支持序数日期 (
YYYY-OOO
)。
示例:
- >>> from datetime import datetime
- >>> datetime.fromisoformat('2011-11-04')
- datetime.datetime(2011, 11, 4, 0, 0)
- >>> datetime.fromisoformat('20111104')
- datetime.datetime(2011, 11, 4, 0, 0)
- >>> datetime.fromisoformat('2011-11-04T00:05:23')
- datetime.datetime(2011, 11, 4, 0, 5, 23)
- >>> datetime.fromisoformat('2011-11-04T00:05:23Z')
- datetime.datetime(2011, 11, 4, 0, 5, 23, tzinfo=datetime.timezone.utc)
- >>> datetime.fromisoformat('20111104T000523')
- datetime.datetime(2011, 11, 4, 0, 5, 23)
- >>> datetime.fromisoformat('2011-W01-2T00:05:23.283')
- datetime.datetime(2011, 1, 4, 0, 5, 23, 283000)
- >>> datetime.fromisoformat('2011-11-04 00:05:23.283')
- datetime.datetime(2011, 11, 4, 0, 5, 23, 283000)
- >>> datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
- datetime.datetime(2011, 11, 4, 0, 5, 23, 283000, tzinfo=datetime.timezone.utc)
- >>> datetime.fromisoformat('2011-11-04T00:05:23+04:00')
- datetime.datetime(2011, 11, 4, 0, 5, 23,
- tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
Added in version 3.7.
在 3.11 版本发生变更: 在之前版本中,此方法仅支持可以由 date.isoformat()
或 datetime.isoformat()
发出的格式。
- classmethod datetime.fromisocalendar(year, week, day)
- 返回以 year, week 和 day 值指明的 ISO 历法日期所对应的
datetime
。 该datetime 对象的非日期部分将使用其标准默认值来填充。 这是函数datetime.isocalendar()
的逆操作。
Added in version 3.8.
- classmethod datetime.strptime(date_string, format)
- 返回一个对应于 date_string,根据 format 进行解析得到的
datetime
对象。
如果 format 不包含微秒或时区信息,这将等价于:
- datetime(*(time.strptime(date_string, format)[0:6]))
如果 date_string 和 format 无法被 time.strptime()
解析或它返回一个不是时间元组的值则将引发 ValueError
。 另请参阅 strftime() 和 strptime() 的行为 和 datetime.fromisoformat()
。
在 3.13 版本发生变更: 现在如果 format 指定了月份日期但没有年份则会发出 DeprecationWarning
。 这是为了避免在代码中当格式缺少年份仅能解析月份和日期时将使用非闰年的默认年份而导致四年轮回的闰年程序错误。 这样的 format 值在 Python 3.15 将可能引发错误。 绕过此问题的办法是始终在你的 format 中包括年份。 如果是解析不带年份的 date_string 值,则在解析之前显式地添加一个属于闰年的年份:
- >>> from datetime import datetime
- >>> date_string = "02/29"
- >>> when = datetime.strptime(f"{date_string};1984", "%m/%d;%Y") # Avoids leap year bug.
- >>> when.strftime("%B %d")
- 'February 29'
类属性:
- datetime.min
- 最早的可表示
datetime
,datetime(MINYEAR, 1, 1, tzinfo=None)
。
- datetime.max
- 最晚的可表示
datetime
,datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo=None)
。
- datetime.resolution
- 两个不相等的
datetime
对象之间可能的最小间隔,timedelta(microseconds=1)
。
实例属性(只读):
- datetime.month
- 1 至 12(含)
- datetime.day
- 返回1到指定年月的天数间的数字。
- datetime.hour
- 取值范围是
range(24)
。
- datetime.minute
- 取值范围是
range(60)
。
- datetime.second
- 取值范围是
range(60)
。
- datetime.microsecond
- 取值范围是
range(1000000)
。
- datetime.tzinfo
- 作为 tzinfo 参数被传给
datetime
构造器的对象,如果没有传入值则为None
。
- datetime.fold
- 取值范围是
[0, 1]
。 用于在重复的时间段中消除边界时间的歧义。 (当夏令时结束时回拨时钟或由于政治原因导致当前时区的 UTC 时差减少就会出现重复时间段。) 取值 0 和 1 分别表示两个相同边界时间表示形式的前一个和后一个时间。
Added in version 3.6.
支持的运算:
运算 | 结果: |
---|---|
datetime2 = datetime1 + timedelta
| (1) |
datetime2 = datetime1 - timedelta
| (2) |
timedelta = datetime1 - datetime2
| (3) |
datetime1 == datetime2
datetime1 != datetime2
| 相等性比较。 (4) |
datetime1 < datetime2
datetime1 > datetime2
datetime1 <= datetime2
datetime1 >= datetime2
| 顺序比较。 (5) |
datetime2
是datetime1
去掉timedelta
时间段的结果,如果timedelta.days > 0
则是在时间线上前进,如果timedelta.days < 0
则时在时间线上后退。 该结果具有与输入的 datetime 相同的tzinfo
属性,并且运算后datetime2 - datetime1 == timedelta
。 如果datetime2.year
将要小于MINYEAR
或大于MAXYEAR
则会引发OverflowError
。 请注意即使输入的是一个感知型对象该方法也不会进行时区调整。计算
datetime2
使得datetime2 + timedelta == datetime1
。 与相加操作一样,结果具有与输入的 datetime 相同的tzinfo
属性,即使输入的是一个感知型对象该方法也不会进行时区调整。从一个
datetime
减去一个datetime
仅对两个操作数均为简单型或均为感知型时有定义。 如果一个是感知型而另一个是简单型,则会引发TypeError
。
如果两个操作数都是简单型,或都是感知型并且具有相同的 tzinfo
属性,则 tzinfo
属性会被忽略,并且结果会是一个使得 datetime2 + t == datetime1
的 timedelta
对象 t
。 在此情况下不会进行时区调整。
如果两者均为感知型且具有不同的 tzinfo
属性,a-b
的效果就如同 a
和 b
首先被转换为简单型 UTC 日期时间。 结果将为 (a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset())
,不同之处在于具体实现绝对不会溢出。
datetime
对象如果在考虑时区的情况下表示相同的日期和时间那么就是相等的。
简单型和感知型 datetime
对象绝不会相等。
如果两个操作数均为感知型,且具有相同的 tzinfo
属性,则 tzinfo
和 fold
属性将被忽略并对基本日期时间值进行比较。 如果两个操作数均为感知型且具有不同的 tzinfo
属性,则比较行为将如同两个操作数首先被转换为 UTC,不同之处是具体实现绝对不会溢出。 具有重复间隔的 datetime
实例绝对不会等于属性其他时区的 datetime
实例。
- 在考虑时区的情况下,当 datetime1 的时间在 datetime2 之前则认为 datetime1 小于 datetime2。
简单型和感知型 datetime
对象之间的顺序比较将会引发 TypeError
。
如果两个操作数均为感知型,且具有相同的 tzinfo
属性,则 tzinfo
和 fold
属性将被忽略并对基本日期时间值进行比较。 如果两个操作数均为感知型且具有不同的 tzinfo
属性,则比较行为将如同两个操作数首先被转换为 UTC 日期时间,不同之处是具体实现绝对不会溢出。
在 3.3 版本发生变更: 感知型和简单型 datetime
实例之间的相等比较不会引发 TypeError
。
在 3.13 版本发生变更: 在 datetime
对象和不属于 datetime
子类的 date
子类的实例之间进行比较时不会再将后者转换为 date
,并忽略时间部分和时区信息。 此默认行为可以通过在子类中重写特殊比较方法来更改。
实例方法:
- datetime.date()
- 返回具有同样 year, month 和 day 值的
date
对象。
- datetime.time()
- 返回具有同样 hour, minute, second, microsecond 和 fold 值的
time
对象。tzinfo
值为None
。 另请参见timetz()
方法。
在 3.6 版本发生变更: fold 值会被复制给返回的 time
对象。
- datetime.timetz()
- 返回具有同样 hour, minute, second, microsecond, fold 和 tzinfo 属性性的
time
对象。 另请参见time()
方法。
在 3.6 版本发生变更: fold 值会被复制给返回的 time
对象。
- datetime.replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0)
- 返回一个具有同样属性值的 datetime,除非通过任何关键字参数为某些属性指定了新值。 请注意可以通过指定
tzinfo=None
来从一个感知型 datetime 创建一个简单型 datetime 而不必转换日期和时间数据。
datetime
对象也被泛型函数 copy.replace()
所支持。
在 3.6 版本发生变更: 增加了 fold 形参。
- datetime.astimezone(tz=None)
- 返回一个具有新的
tzinfo
属性 tz 的datetime
对象,并会调整日期和时间数据使得结果对应的 UTC 时间与 self 相同,但为 tz 时区的本地时间。
如果给出了 tz,则它必须是一个 tzinfo
子类的实例,并且其 utcoffset()
和 dst()
方法不可返回 None
。 如果 self 为简单型,它会被假定为基于系统时区表示的时间。
如果调用时不传入参数 (或传入 tz=None
) 则将假定目标时区为系统的本地时区。 转换后 datetime 实例的 .tzinfo
属性将被设为一个 timezone
实例,时区名称和时差值将从 OS 获取。
如果 self.tzinfo
为 tz,self.astimezone(tz)
等于 self: 不会对日期或时间数据进行调整。 否则结果为 tz 时区的本地时间,代表的 UTC 时间与 self 相同:在 astz = dt.astimezone(tz)
之后,astz - astz.utcoffset()
将具有与 dt - dt.utcoffset()
相同的日期和时间数据。
如果你只是想要附加一个 timezone
对象 tz 到一个 datetime 对象 dt 而不调整日期和时间数据,请使用 dt.replace(tzinfo=tz)
。 如果你只是想要从一个感知型 datetime 对象 dt 移除 timezone
对象,请使用 dt.replace(tzinfo=None)
。
请注意默认的 tzinfo.fromutc()
方法在 tzinfo
的子类中可以被重写,从而影响 astimezone()
的返回结果。 如果忽略出错的情况,astimezone()
的行为就类似于:
- def astimezone(self, tz):
- if self.tzinfo is tz:
- return self
- # 将 self 转换为 UTC,并附加新的时区对象
- utc = (self - self.utcoffset()).replace(tzinfo=tz)
- # 从 UTC 转换为 tz 的地方时。
- return tz.fromutc(utc)
在 3.3 版本发生变更: tz 现在可以被省略。
在 3.6 版本发生变更: astimezone()
方法可以由简单型实例调用,这将假定其表示本地时间。
- datetime.utcoffset()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.utcoffset(self)
,并且在后者不返回None
或者一个幅度小于一天的timedelta
对象时将引发异常。
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
- datetime.dst()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.dst(self)
,并且在后者不返回None
或者一个幅度小于一天的timedelta
对象时将引发异常。
在 3.7 版本发生变更: DST 差值不再限制为一个整数分钟值。
- datetime.tzname()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.tzname(self)
,如果后者不返回None
或者一个字符串对象则将引发异常。
- datetime.timetuple()
- 返回一个
time.struct_time
,即time.localtime()
所返回的类型。
d.timetuple()
等价于:
- time.struct_time((d.year, d.month, d.day,
- d.hour, d.minute, d.second,
- d.weekday(), yday, dst))
其中 yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1
是日期在当前年份中的序号,起始值 1 表示 1 月 1 日。 结果的 tm_isdst
旗标会根据 dst()
方法来设定:如果 tzinfo
为 None
或 dst()
返回 None
,则 tm_isdst
将设为 -1
;否则如果 dst()
返回非零值,则 tm_isdst
将设为 1;在其他情况下 tm_isdst
将设为 0。
- datetime.utctimetuple()
- 如果
datetime
实例d
为简单型,这将与d.timetuple()
相当,区别在于tm_isdst
会被强制设为 0 而无视d.dst()
返回值。 DST 对于 UTC 时间必定无效。
如果 d
为感知型,则 d
会通过减去 d.utcoffset()
来标准化为 UTC 时间,并返回表示该标准化时间的 time.struct_time
。 tm_isdst
将被强制设为 0。 请注意如果 d.year
为 MINYEAR
或 MAXYEAR
且 UTC 调整超出一年的边界则可能引发 OverflowError
。
警告
由于简单型 datetime
对象会被许多 datetime
方法当作本地时间来处理,最好是使用感知型日期时间来表示 UTC 时间;因此,使用 datetime.utctimetuple()
可能会给出误导性的结果。 如果你有一个表示 UTC 的简单型 datetime
,请使用 datetime.replace(tzinfo=timezone.utc)
将其改为感知型,这样你才能使用 datetime.timetuple()
。
- datetime.toordinal()
- 返回日期的预期格列高利历序号。 与
self.date().toordinal()
相同。
- datetime.timestamp()
- 返回对应于
datetime
实例的 POSIX 时间戳。 此返回值是与time.time()
返回值类似的float
对象。
简单型 datetime
实例会被假定为代表本地时间并且此方法依赖于平台的 C mktime()
函数来执行转换。 由于在许多平台上 datetime
支持的取值范围比 mktime()
更广,对于极其遥远的过去或未来此方法可能会引发 OverflowError
或 OSError
。
对于感知型 datetime
实例,返回值的计算方式为:
- (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()
Added in version 3.3.
在 3.6 版本发生变更: timestamp()
方法使用 fold
属性来消除重复间隔中的时间歧义。
备注
没有一个方法能直接从表示 UTC 时间的简单型 datetime
实例获取 POSIX 时间戳。 如果你的应用程序使用此惯例并且你的系统时区不是设为 UTC,你可以通过提供 tzinfo=timezone.utc
来获取 POSIX 时间戳:
- timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
或者通过直接计算时间戳:
- timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
- datetime.weekday()
- 返回一个整数代表星期几,星期一为 0,星期天为 6。 相当于
self.date().weekday()
。 另请参阅isoweekday()
。
- datetime.isoweekday()
- 返回一个整数代表星期几,星期一为 1,星期天为 7。 相当于
self.date().isoweekday()
。 另请参阅weekday()
,isocalendar()
。
- datetime.isocalendar()
- 返回一个由三部分组成的 named tuple:
year
,week
和weekday
。 等同于self.date().isocalendar()
。
- datetime.isoformat(sep='T', timespec='auto')
返回一个以 ISO 8601 格式表示的日期和时间字符串:
YYYY-MM-DDTHH:MM:SS.ffffff
,如果microsecond
不为 0YYYY-MM-DDTHH:MM:SS
,如果microsecond
为 0
如果 utcoffset()
返回值不为 None
,则添加一个字符串来给出 UTC 时差:
YYYY-MM-DDTHH:MM:SS.ffffff+HH:MM[:SS[.ffffff]]
,如果microsecond
不为 0YYYY-MM-DDTHH:MM:SS+HH:MM[:SS[.ffffff]]
,如果microsecond
为 0
示例:
- >>> from datetime import datetime, timezone
- >>> datetime(2019, 5, 18, 15, 17, 8, 132263).isoformat()
- '2019-05-18T15:17:08.132263'
- >>> datetime(2019, 5, 18, 15, 17, tzinfo=timezone.utc).isoformat()
- '2019-05-18T15:17:00+00:00'
可选参数 sep (默认为 'T'
) 为单个分隔字符,会被放在结果的日期和时间两部分之间。 例如:
- >>> from datetime import tzinfo, timedelta, datetime
- >>> class TZ(tzinfo):
- ... """A time zone with an arbitrary, constant -06:39 offset."""
- ... def utcoffset(self, dt):
- ... return timedelta(hours=-6, minutes=-39)
- ...
- >>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
- '2002-12-25 00:00:00-06:39'
- >>> datetime(2009, 11, 27, microsecond=100, tzinfo=TZ()).isoformat()
- '2009-11-27T00:00:00.000100-06:39'
可选参数 timespec 要包含的额外时间组件值 (默认为 'auto'
)。它可以是以下值之一:
'auto'
: 如果microsecond
为 0 则与'seconds'
相同,否则与'microseconds'
相同。'hours'
: 以两个数码的HH
格式 包含hour
。'milliseconds'
: 包含完整时间,但将秒值的小数部分截断至毫秒。 格式为HH:MM:SS.sss
。'microseconds'
: 以HH:MM:SS.ffffff
格式包含完整时间。
备注
排除掉的时间部分将被截断,而不是被舍入。
对于无效的 timespec 参数将引发 ValueError
:
- >>> from datetime import datetime
- >>> datetime.now().isoformat(timespec='minutes')
- '2002-12-25T00:00'
- >>> dt = datetime(2015, 1, 1, 12, 30, 59, 0)
- >>> dt.isoformat(timespec='microseconds')
- '2015-01-01T12:30:59.000000'
在 3.6 版本发生变更: 增加了 timespec 形参。
- datetime.str()
- 对于
datetime
实例d
,str(d)
等价于d.isoformat(' ')
。
- datetime.ctime()
- 返回一个表示日期和时间的字符串:
- >>> from datetime import datetime
- >>> datetime(2002, 12, 4, 20, 30, 40).ctime()
- 'Wed Dec 4 20:30:40 2002'
输出字符串将 并不 包括时区信息,无论输入的是感知型还是简单型。
d.ctime()
等效于:
- time.ctime(time.mktime(d.timetuple()))
在原生 C ctime()
函数遵循 C 标准的平台上 (time.ctime()
会发起对该函数的调用,但 datetime.ctime()
并不会) 。
- datetime.strftime(format)
- 返回一个由显式格式字符串所控制的,代表日期和时间的字符串。 另请参阅 strftime() 和 strptime() 的行为 和
datetime.isoformat()
。
- datetime.format(format)
- 与
datetime.strftime()
相同。 此方法使得在 格式化字符串字面值 中以及使用str.format()
时为datetime
对象指定格式字符串成为可能。 另请参阅 strftime() 和 strptime() 的行为 和datetime.isoformat()
。
用法示例: datetime
使用 datetime
对象的例子:
- >>> from datetime import datetime, date, time, timezone
- >>> # 使用 datetime.combine()
- >>> d = date(2005, 7, 14)
- >>> t = time(12, 30)
- >>> datetime.combine(d, t)
- datetime.datetime(2005, 7, 14, 12, 30)
- >>> # 使用 datetime.now()
- >>> datetime.now()
- datetime.datetime(2007, 12, 6, 16, 29, 43, 79043) # GMT +1
- >>> datetime.now(timezone.utc)
- datetime.datetime(2007, 12, 6, 15, 29, 43, 79060, tzinfo=datetime.timezone.utc)
- >>> # 使用 datetime.strptime()
- >>> dt = datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
- >>> dt
- datetime.datetime(2006, 11, 21, 16, 30)
- >>> # 使用 datetime.timetuple() 获取由所有属性组成的元组
- >>> tt = dt.timetuple()
- >>> for it in tt:
- ... print(it)
- ...
- 2006 # 年
- 11 # 月
- 21 # 日
- 16 # 时
- 30 # 分
- 0 # 秒
- 1 # 星期序号 (0 = Monday)
- 325 # 自 1 月 1 日开始的天数
- -1 # 夏令时 - 方法 tzinfo.dst() 返回 None
- >>> # ISO 格式的日期
- >>> ic = dt.isocalendar()
- >>> for it in ic:
- ... print(it)
- ...
- 2006 # ISO 年份
- 47 # ISO 星期
- 2 # ISO 星期序号
- >>> # 格式化日期时间
- >>> dt.strftime("%A, %d. %B %Y %I:%M%p")
- 'Tuesday, 21. November 2006 04:30PM'
- >>> 'The {1} is {0:%d}, the {2} is {0:%B}, the {3} is {0:%I:%M%p}.'.format(dt, "day", "month", "time")
- 'The day is 21, the month is November, the time is 04:30PM.'
以下示例定义了一个 tzinfo
子类,它捕获 Kabul, Afghanistan 时区的信息,该时区使用 +4 UTC 直到 1945 年,之后则使用 +4:30 UTC:
- from datetime import timedelta, datetime, tzinfo, timezone
- class KabulTz(tzinfo):
- # 喀布尔曾使用 +4 直到 1945 年,后改为 +4:30
- UTC_MOVE_DATE = datetime(1944, 12, 31, 20, tzinfo=timezone.utc)
- def utcoffset(self, dt):
- if dt.year < 1945:
- return timedelta(hours=4)
- elif (1945, 1, 1, 0, 0) <= dt.timetuple()[:5] < (1945, 1, 1, 0, 30):
- # 带有歧义(“虚幻”)的半小时区间代表
- # 由于从 +4 改为 +4:30 导致的时间‘折叠’。
- # 如果 dt 落在此虚幻区间,则使用该折叠
- # 确定如何计算。 参见 PEP495。
- return timedelta(hours=4, minutes=(30 if dt.fold else 0))
- else:
- return timedelta(hours=4, minutes=30)
- def fromutc(self, dt):
- # 遵循与在 datetime.tzinfo 中相同的效力
- if not isinstance(dt, datetime):
- raise TypeError("fromutc() requires a datetime argument")
- if dt.tzinfo is not self:
- raise ValueError("dt.tzinfo is not self")
- # 需要一个针对 fromutc 的自定义实现
- # 因为此函数的输入是 utc 日期时间值
- # 但其 tzinfo 设为 self。
- # 参见 datetime.astimezone 或 fromtimestamp。
- if dt.replace(tzinfo=timezone.utc) >= self.UTC_MOVE_DATE:
- return dt + timedelta(hours=4, minutes=30)
- else:
- return dt + timedelta(hours=4)
- def dst(self, dt):
- # 喀布尔不实行夏令时。
- return timedelta(0)
- def tzname(self, dt):
- if dt >= self.UTC_MOVE_DATE:
- return "+04:30"
- return "+04"
上述 KabulTz
的用法:
- >>> tz1 = KabulTz()
- >>> # 修改前的日期时间
- >>> dt1 = datetime(1900, 11, 21, 16, 30, tzinfo=tz1)
- >>> print(dt1.utcoffset())
- 4:00:00
- >>> # 修改后的日期时间
- >>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=tz1)
- >>> print(dt2.utcoffset())
- 4:30:00
- >>> # 将日期时间转换至另一个时区
- >>> dt3 = dt2.astimezone(timezone.utc)
- >>> dt3
- datetime.datetime(2006, 6, 14, 8, 30, tzinfo=datetime.timezone.utc)
- >>> dt2
- datetime.datetime(2006, 6, 14, 13, 0, tzinfo=KabulTz())
- >>> dt2 == dt3
- True
time
对象
一个 time
对象代表某日的(本地)时间,它独立于任何特定日期,并可通过 tzinfo
对象来调整。
- class datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)
所有参数都是可选的。 tzinfo 可以是
None
,或者是一个tzinfo
子类的实例。 其余的参数必须是在下面范围内的整数:0 <= hour < 24
,0 <= minute < 60
,0 <= second < 60
,0 <= microsecond < 1000000
,fold in [0, 1]
.
如果给出一个此范围以外的参数,则会引发 ValueError
。 所有参数默认值均为 0 但 tzinfo 除外,其默认值为 None
。
类属性:
- time.min
- 早最的可表示
time
,time(0, 0, 0, 0)
。
- time.max
- 最晚的可表示
time
,time(23, 59, 59, 999999)
。
实例属性(只读):
- time.hour
- 取值范围是
range(24)
。
- time.minute
- 取值范围是
range(60)
。
- time.second
- 取值范围是
range(60)
。
- time.microsecond
- 取值范围是
range(1000000)
。
- time.tzinfo
- 作为 tzinfo 参数被传给
time
构造器的对象,如果没有传入值则为None
。
- time.fold
- 取值范围是
[0, 1]
。 用于在重复的时间段中消除边界时间的歧义。 (当夏令时结束时回拨时钟或由于政治原因导致当前时区的 UTC 时差减少就会出现重复时间段。) 取值 0 和 1 分别表示两个相同边界时间表示形式的前一个和后一个时间。
Added in version 3.6.
time
对象支持相等和顺序比较,当 a
的时间在 b
之前则认为 a
小于 b
。
简单型和感知型 time
对象绝对不会相等。 简单型和感知型 time
对象之间的顺序比较将会引发 TypeError
。
如果两个操作数均为感知型,且具有相同的 tzinfo
属性,则 tzinfo
和 fold
属性会被忽略并对基本时间值进行比较。 如果两个操作数均为感知型且具有不同的 tzinfo
属性,则两个操作数将首先通过减去它们的 UTC 时差(从 self.utcoffset()
获取)来进行调整。
在 3.3 版本发生变更: 感知型和简单型 time
实例之间的相等性比较不会引发 TypeError
。
在布尔运算时,time
对象总是被视为真值。
在 3.5 版本发生变更: 在 Python 3.5 之前,如果一个 time
对象代表 UTC 午夜零时则会被视为假值。 此行为被认为容易引发困惑和错误,因此从 Python 3.5 起已被去除。 详情参见 bpo-13936 [https://bugs.python.org/issue?@action=redirect&bpo=13936]。
其他构造方法:
- classmethod time.fromisoformat(time_string)
- 返回一个对应于以任何有效的 ISO 8601 格式给出的 time_string 的
time
,下列格式除外:
时区时差可能会有带小数的秒值。
打头的
T
,通常在当日期和时间之间可能存在歧义时才有必要,不是必需的。带小数的秒值可以有任意多位数码(超过 6 位将被截断)。
带小数的时和分是不受支持的。
示例:
- >>> from datetime import time
- >>> time.fromisoformat('04:23:01')
- datetime.time(4, 23, 1)
- >>> time.fromisoformat('T04:23:01')
- datetime.time(4, 23, 1)
- >>> time.fromisoformat('T042301')
- datetime.time(4, 23, 1)
- >>> time.fromisoformat('04:23:01.000384')
- datetime.time(4, 23, 1, 384)
- >>> time.fromisoformat('04:23:01,000384')
- datetime.time(4, 23, 1, 384)
- >>> time.fromisoformat('04:23:01+04:00')
- datetime.time(4, 23, 1, tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
- >>> time.fromisoformat('04:23:01Z')
- datetime.time(4, 23, 1, tzinfo=datetime.timezone.utc)
- >>> time.fromisoformat('04:23:01+00:00')
- datetime.time(4, 23, 1, tzinfo=datetime.timezone.utc)
Added in version 3.7.
在 3.11 版本发生变更: 在之前版本中,此方法仅支持可由 time.isoformat()
发出的格式。
实例方法:
- time.replace(hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0)
- 返回一个具有同样属性值的
time
,除非通过任何关键字参数指定了某些属性值。 请注意可以通过指定tzinfo=None
从一个感知型time
创建一个简单型time
,而不必转换时间数据。
time
对象也被泛型函数 copy.replace()
所支持。
在 3.6 版本发生变更: 增加了 fold 形参。
- time.isoformat(timespec='auto')
返回表示为下列 ISO 8601 格式之一的时间字符串:
HH:MM:SS.ffffff
,如果microsecond
不为 0HH:MM:SS
,如果microsecond
为 0HH:MM:SS.ffffff+HH:MM[:SS[.ffffff]]
,如果utcoffset()
不返回None
HH:MM:SS+HH:MM[:SS[.ffffff]]
,如果microsecond
为 0 并且utcoffset()
不返回None
可选参数 timespec 要包含的额外时间组件值 (默认为 'auto'
)。它可以是以下值之一:
'auto'
: 如果microsecond
为 0 则与'seconds'
相同,否则与'microseconds'
相同。'hours'
: 以两个数码的HH
格式 包含hour
。'milliseconds'
: 包含完整时间,但将秒值的小数部分截断至毫秒。 格式为HH:MM:SS.sss
。'microseconds'
: 以HH:MM:SS.ffffff
格式包含完整时间。
备注
排除掉的时间部分将被截断,而不是被舍入。
对于无效的 timespec 参数将引发 ValueError
。
示例:
- >>> from datetime import time
- >>> time(hour=12, minute=34, second=56, microsecond=123456).isoformat(timespec='minutes')
- '12:34'
- >>> dt = time(hour=12, minute=34, second=56, microsecond=0)
- >>> dt.isoformat(timespec='microseconds')
- '12:34:56.000000'
- >>> dt.isoformat(timespec='auto')
- '12:34:56'
在 3.6 版本发生变更: 增加了 timespec 形参。
- time.str()
- 对于时间对象
t
,str(t)
等价于t.isoformat()
。
- time.strftime(format)
- 返回一个由显式格式字符串所控制的,代表时间的字符串。 另请参阅 strftime() 和 strptime() 的行为 和
time.isoformat()
。
- time.format(format)
- 与
time.strftime()
相同。 此方法使得在 格式化字符串字面值 中以及使用str.format()
时为time
对象指定格式字符串成为可能。 另请参阅 strftime() 和 strptime() 的行为 和time.isoformat()
。
- time.utcoffset()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.utcoffset(None)
,并且在后者不返回None
或一个幅度小于一天的 atimedelta
对象时将引发异常。
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
- time.dst()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.dst(None)
,并且在后者不返回None
或者一个幅度小于一天的timedelta
对象时将引发异常。
在 3.7 版本发生变更: DST 差值不再限制为一个整数分钟值。
- time.tzname()
- 如果
tzinfo
为None
,则返回None
,否则返回self.tzinfo.tzname(None)
,如果后者不返回None
或者一个字符串对象则将引发异常。
用法示例: time
使用 time
对象的例子:
- >>> from datetime import time, tzinfo, timedelta
- >>> class TZ1(tzinfo):
- ... def utcoffset(self, dt):
- ... return timedelta(hours=1)
- ... def dst(self, dt):
- ... return timedelta(0)
- ... def tzname(self,dt):
- ... return "+01:00"
- ... def __repr__(self):
- ... return f"{self.__class__.__name__}()"
- ...
- >>> t = time(12, 10, 30, tzinfo=TZ1())
- >>> t
- datetime.time(12, 10, 30, tzinfo=TZ1())
- >>> t.isoformat()
- '12:10:30+01:00'
- >>> t.dst()
- datetime.timedelta(0)
- >>> t.tzname()
- '+01:00'
- >>> t.strftime("%H:%M:%S %Z")
- '12:10:30 +01:00'
- >>> 'The {} is {:%H:%M}.'.format("time", t)
- 'The time is 12:10.'
tzinfo
对象
- class datetime.tzinfo
- 这是一个抽象基类,也就是说该类不应被直接实例化。 请定义
tzinfo
的子类来捕获有关特定时区的信息。
tzinfo
的(某个实体子类)的实例可以被传给 datetime
和 time
对象的构造器。 这些对象会将它们的属性视为对应于本地时间,并且 tzinfo
对象支持展示本地时间与 UTC 的差值、时区名称以及 DST 差值的方法,都是与传给它们的日期或时间对象的相对值。
你需要派生一个实体子类,并且(至少)提供你使用 datetime
方法所需要的标准 tzinfo
方法的实现。 datetime
模块提供了 timezone
,这是 tzinfo
的一个简单实体子类,它能以与 UTC 的固定差值来表示不同的时区,例如 UTC 本身或北美的 EST 和 EDT。
对于封存操作的特殊要求:一个 tzinfo
子类必须具有可不带参数调用的 __init__()
方法,否则它虽然可以被封存,但可能无法再次解封。 这是个技术性要求,在未来可能会被取消。
一个 tzinfo
的实体子类可能需要实现以下方法。 具体需要实现的方法取决于感知型 datetime
对象如何使用它。 如果有疑问,可以简单地全部实现它们。objects. If in doubt, simply implement all of them.
- tzinfo.utcoffset(dt)
- 将本地时间与 UTC 时差返回为一个
timedelta
对象,如果本地时区在 UTC 以东则为正值。 如果本地时区在 UTC 以西则为负值。
这表示与 UTC 的 总计 时差;举例来说,如果一个 tzinfo
对象同时代表时区和 DST 调整,则 utcoffset()
应当返回两者的和。 如果 UTC 时差不确定则返回 None
。 在其他情况下返回值必须为一个 timedelta
对象,其取值严格限制于 -timedelta(hours=24)
和 timedelta(hours=24)
之间(差值的幅度必须小于一天)。 大多数 utcoffset()
的实现看起来可能像是以下两者之一:
- return CONSTANT # 固定偏移类
- return CONSTANT + self.dst(dt) # 夏令时感知类
如果 utcoffset()
返回值不为 None
,则 dst()
也不应返回 None
。
默认的 utcoffset()
实现会引发 NotImplementedError
。
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
- tzinfo.dst(dt)
- 将夏令时(DST)调整返回为一个
timedelta
对象,如果 DST 信息未知则返回None
。
如果 DST 未启用则返回 timedelta(0)
。 如果 DST 已启用,则将差值作为一个 timedelta
对象返回(请参阅 utcoffset()
了解详情)。 请注意 DST 差值如果可用,就会直接被加入 utcoffset()
所返回的 UTC 时差,因此无需额外查询 dst()
,除非你希望单独获取 DST 信息。 例如,datetime.timetuple()
会调用其 tzinfo
属性的 dst()
方法来确定应该如何设置 tm_isdst
旗标,而 tzinfo.fromutc()
会调用 dst()
来在跨越时区时处理 DST 的改变。
一个可以同时处理标准时和夏令时的 tzinfo
子类的实例 tz 必须在此情形中保持一致:
tz.utcoffset(dt) - tz.dst(dt)
必须为具有 dt.tzinfo == tz
的每个 datetime
dt 返回同样的结果。 对于同样的 tzinfo
子类,此表达式会产生特定时区的“标准时差”,它不应依赖于具体日期或时间,而只依赖于地理位置。 datetime.astimezone()
的实现依赖于此方法,但无法检测违反规则的情况;确保符合规则是程序员的责任。 如果一个 tzinfo
子类不能保证这一点,也许可以重写 tzinfo.fromutc()
的默认实现以便在任何情况下与 astimezone()
正确配合。
大多数 dst()
的实现可能会如以下两者之一:
- def dst(self, dt):
- # 固定偏移类:不考虑夏令时
- return timedelta(0)
或者:
- def dst(self, dt):
- # 此代码根据输入的 dt.year 设置时区的夏令时
- # 切换的开始和结束时刻 dston 和 dstoff,并以
- # 标准地方时表示。
- 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"<code>,
"UTC","-500"
,"-5:00"
,"EDT"
,"US/Eastern"
,"America/New York"
都是有效的返回值。 如果字符串名称未知则返回None
。 请注意这是一个方法而不是一个固定的字符串,这主要是因为某些tzinfo
子类可能需要根据所传入的特定 dt 值返回不同的名称,特别是在tzinfo
类要负责处理夏令时的场合中。
默认的 tzname()
实现会引发 NotImplementedError
。
这些方法会被 datetime
或 time
对象调用,用来与它们的同名方法相对应。 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()
的目标是调整日期和时间数据,返回一个等价的表示 self 的本地时间的 datetime。
大多数 tzinfo
子类应该能够毫无问题地继承默认的 fromutc()
实现。 它的健壮性足以处理固定差值的时区以及同时负责标准时和夏令时的时区,对于后者甚至还能处理 DST 转换时间在各个年份有变化的情况。 一个默认 fromutc()
实现可能无法在所有情况下正确处理的例子是(与 UTC 的)标准时差取决于所经过的特定日期和时间,这种情况可能由于政治原因而出现。 默认的 astimezone()
和 fromutc()
实现可能无法生成你希望的结果,如果这个结果恰好是跨越了标准时差发生改变的时刻当中的某个小时值的话。
忽略针对错误情况的代码,默认 fromutc()
实现的行为方式如下:
- def fromutc(self, dt):
- # 如果 dt.tzinfo 不为 self 则引发 ValueError
- dtoff = dt.utcoffset()
- dtdst = dt.dst()
- # 如果 dtoff 为 None 或 dtdst 为 None 则引发 ValueError
- delta = dtoff - dtdst # 这是 self 的标准偏移
- if delta:
- dt += delta # 转换为标准地方时
- dtdst = dt.dst()
- # 如果 dtdst 为 None 则引发 ValueError
- 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)
- # 一个考虑系统平台地方时处理方式的类。
- # (可能导致在 UTC 时差和/或夏令时规则
- # 曾经发生过变化的时区的某些历史时间
- # 出现错误的值。)
- 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
- # 删除时间折叠
- 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()
- # 针对美国各大时区当前夏令时规则的完整实现。
- 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 夏令时规则
- #
- # 这是一个有关美国夏令时起止时间的有所简化的规则集
- # (即在某些情况下可能出错。)要获取最新的完整夏令时
- # 规则和时区定义集,请访问 Olson 数据库 (或尝试 pytz):
- # http://www.twinsun.com/tz/tz-link.htm
- # https://sourceforge.net/projects/pytz/ (更新可能不及时)
- #
- # 在美国,从 2007 年起,夏令时开始于 3 月的第二个星期天
- # 上午 2 时 (标准时),即从 3 月 8 日起的第一个星期天。
- DSTSTART_2007 = datetime(1, 3, 8, 2)
- # 结束于 11 月的第一天星期天上午 2 时 (夏令时)。
- DSTEND_2007 = datetime(1, 11, 1, 2)
- # 从 1987 到 2006 年,夏令时开始于 4 月的第一个星期天
- # 上午 2 时 (标准时),结束于 10 月的最后一个星期天上午 2 时
- # (夏令时),即从 10 月 25 日起的第一个星期天。
- DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
- DSTEND_1987_2006 = datetime(1, 10, 25, 2)
- # 从 1967 到 1986 年,夏令时开始于 4 月的最后一个星期天
- # 上午 2 时 (标准时),(即从 4 月 24 日起的第一个星期天)
- # 结束于 10 月的最后一个星期天上午 2 时 (夏令时),
- # 即从 10 月 25 日起的第一个星期天。
- DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
- DSTEND_1967_1986 = DSTEND_1987_2006
- def us_dst_range(year):
- # 找到美国夏令时的起止时间。 针对 1967 之前的年份,
- # 将为非夏令时返回 start = end。
- 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:
- # 对于某种或两种情况,可以考虑在此设置异常。
- # 具体取决于你想如何处理它们。
- # 默认的 fromutc() 实现 (由默认的 astimezone() 实现调用)
- # 将传入一个 dt.tzinfo 为 self 的日期时间。
- return ZERO
- assert dt.tzinfo is self
- start, end = us_dst_range(dt.year)
- # 无法将简单型与感知型对象进行比较,
- # 因此先从 dt 移除时区。
- dt = dt.replace(tzinfo=None)
- if start + HOUR <= dt < end - HOUR:
- # 夏令时已生效。
- return HOUR
- if end - HOUR <= dt < end:
- # 折叠 (有歧义的小时值):使用 dt.fold 来消除歧义。
- return ZERO if dt.fold else HOUR
- if start <= dt < start + HOUR:
- # 空档 (不存在的小时值):逆向折叠规则。
- return HOUR if dt.fold else ZERO
- # 夏令时已结束。
- 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:
- # 重复的小时值
- return std_time.replace(fold=1)
- if std_time < start or dst_time >= end:
- # 标准时
- return std_time
- if start <= std_time < end - HOUR:
- # 夏令时
- 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 从三月的第二个星期天 1:59 (EST) 之后一分钟开始,并在十一月的第一天星期天 1:59 (EDT) 之后一分钟结束:
- 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 开始时(即 "start" 行),本地时钟从 1:59 跳到 3:00。 形式为 2:MM 的时间值在那一天是没有意义的,因此在 DST 开始那一天 astimezone(Eastern)
不会输出包含 hour == 2
的结果。 例如,在 2016 年春季时钟向前调整时,我们得到:
- >>> 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 结束时(见 "end" 行),会有更糟糕的潜在问题:本地时间值中有一个小时是不可能没有歧义的:夏令时的最后一小时。 即以北美东部时间表示当天夏令时结束时的形式为 5:MM UTC 的时间。 本地时钟从 1:59(夏令时)再次跳回到 1:00(标准时)。 形式为 1:MM 的本地时间就是有歧义的。 此时 astimezone()
是通过将两个相邻的 UTC 小时映射到两个相同的本地小时来模仿本地时钟的行为。 在这个北美东部时间的示例中,形式为 5:MM 和 6:MM 的 UTC 时间在转换为北美东部时间时都将被映射到 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 小时) 的类时是不会有歧义的)。
参见
zoneinfo
datetime
模块有一个基本timezone
类(用来处理任意与 UTC 的固定时差)及其timezone.utc
属性(UTCtimezone
实例)。
zoneinfo
为 Python 带来了 IANA时区数据库 (也被称为 Olson 数据库),推荐使用它。
- IANA 时区数据库 [https://www.iana.org/timezones]
- 该时区数据库 (通常称为 tz, tzdata 或 zoneinfo) 包含大量代码和数据用来表示全球许多有代表性的地点的本地时间的历史信息。 它会定期进行更新以反映各政治实体对时区边界、UTC 差值和夏令时规则的更改。
timezone
对象
timezone
类是 tzinfo
的子类,它的每个实例都代表一个以与 UTC 的固定时差来定义的时区。
此类的对象不可被用于代表某些特殊地点的时区信息,这些地点在一年的不同日期会使用不同的时差,或是在历史上对民用时间进行过调整。
- class datetime.timezone(offset, name=None)
- offset 参数必须指定为一个
timedelta
对象,表示本地时间与 UTC 的时差。 它必须严格限制于-timedelta(hours=24)
和timedelta(hours=24)
之间,否则会引发ValueError
。
name 参数是可选的。 如果指定则必须为一个字符串,它将被用作 datetime.tzname()
方法的返回值。
Added in version 3.2.
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
- timezone.utcoffset(dt)
- 返回当
timezone
实例被构造时指定的固定值。
dt 参数会被忽略。 返回值是一个 timedelta
实例,其值等于本地时间与 UTC 之间的时差。
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
- timezone.tzname(dt)
- 返回当
timezone
实例被构造时指定的固定值。
如果没有在构造器中提供 name,则 tzname(dt)
所返回的名称将根据 offset
值按以下规则生成。 如果 offset 为 timedelta(0)
,则名称为“UTC”,否则为字符串 UTC±HH:MM
,其中 ± 为 offset
的正负符号,HH 和 MM 分别为表示 offset.hours
和 offset.minutes
的两个数码。
在 3.6 版本发生变更: 由 offset=timedelta(0)
生成的名称现在是简单的 'UTC'
,而不是 'UTC+00:00'
。
- timezone.dst(dt)
- 总是返回
None
。
- timezone.fromutc(dt)
- 返回
dt + offset
。 dt 参数必须为一个感知型datetime
实例,其中tzinfo
值设为self
。
类属性:
- timezone.utc
- UTC 时区,
timezone(timedelta(0))
。
strftime()
和 strptime()
的行为
date
, datetime
和 time
对象都支持 strftime(format)
方法,可用来创建由一个显式格式字符串所控制的表示时间的字符串。
相反地,datetime.strptime()
类会根据表示日期和时间的字符串和相应的格式字符串来创建一个 datetime
对象。
下表提供了 strftime()
与 strptime()
的高层级比较:
strftime
|
strptime
| |
---|---|---|
用法 | 根据给定的格式将对象转换为字符串 |
将字符串解析为给定相应格式的 datetime 对象
|
方法类型 | 实例方法 | 类方法 |
方法 |
date ; datetime ; time
|
datetime
|
签名 |
strftime(format)
|
strptime(date_string, format)
|
strftime()
和 strptime()
格式码
这些方法接受可被用于解析和格式化日期的格式代码:
- >>> datetime.strptime('31/01/22 23:59:59.999999',
- ... '%d/%m/%y %H:%M:%S.%f')
- datetime.datetime(2022, 1, 31, 23, 59, 59, 999999)
- >>> _.strftime('%a %d %b %Y, %I:%M%p')
- 'Mon 31 Jan 2022, 11:59PM'
以下列表显示了 1989 版 C 标准所要求的全部格式代码,它们在带有标准 C 实现的所有平台上均可用。
指示符 | 含意 | 示例 | 备注 |
---|---|---|---|
%a
| 当地工作日的缩写。 | Sun, Mon, …, Sat (en_US); So, Mo, …, Sa (de_DE) | (1) |
%A
| 本地化的星期中每日的完整名称。 | Sunday, Monday, …, Saturday (en_US); Sonntag, Montag, …, Samstag (de_DE) | (1) |
%w
| 以十进制数显示的工作日,其中0表示星期日,6表示星期六。 | 0, 1, …, 6 | |
%d
| 补零后,以十进制数显示的月份中的一天。 | 01, 02, …, 31 | (9) |
%b
| 当地月份的缩写。 | Jan, Feb, …, Dec (en_US); Jan, Feb, …, Dez (de_DE) | (1) |
%B
| 本地化的月份全名。 | January, February, …, December (en_US); Januar, Februar, …, Dezember (de_DE) | (1) |
%m
| 补零后,以十进制数显示的月份。 | 01, 02, …, 12 | (9) |
%y
| 补零后,以十进制数表示的,不带世纪的年份。 | 00, 01, …, 99 | (9) |
%Y
| 十进制数表示的带世纪的年份。 | 0001, 0002, …, 2013, 2014, …, 9998, 9999 | (2) |
%H
| 以补零后的十进制数表示的小时(24 小时制)。 | 00, 01, …, 23 | (9) |
%I
| 以补零后的十进制数表示的小时(12 小时制)。 | 01, 02, …, 12 | (9) |
%p
| 本地化的 AM 或 PM 。 | AM, PM (en_US); am, pm (de_DE) | (1), (3) |
%M
| 补零后,以十进制数显示的分钟。 | 00, 01, …, 59 | (9) |
%S
| 补零后,以十进制数显示的秒。 | 00, 01, …, 59 | (4), (9) |
%f
| 微秒作为一个十进制数,零填充到 6 位。 | 000000, 000001, …, 999999 | (5) |
%z
|
UTC 偏移量,格式为 ±HHMM[SS[.ffffff]] (如果是简单型对象则为空字符串)。
| (空), +0000, -0400, +1030, +063415, -030712.345216 | (6) |
%Z
| 时区名称(如果对象为简单型则为空字符串)。 | (空), UTC, GMT | (6) |
%j
| 以补零后的十进制数表示的一年中的日序号。 | 001, 002, …, 366 | (9) |
%U
| 以补零后的十进制数表示的一年中的周序号(星期日作为每周的第一天)。 在新的一年中第一个星期日之前的所有日子都被视为是在第 0 周。 | 00, 01, …, 53 | (7), (9) |
%W
| 以补零后的十进制数表示的一年中的周序号(星期一作为每周的第一天)。 在新的一年中第一个星期一之前的所有日子都被视为是在第 0 周。 | 00, 01, …, 53 | (7), (9) |
%c
| 本地化的适当日期和时间表示。 | Tue Aug 16 21:30:00 1988 (en_US); Di 16 Aug 21:30:00 1988 (de_DE) | (1) |
%x
| 本地化的适当日期表示。 | 08/16/88 (None); 08/16/1988 (en_US); 16.08.1988 (de_DE) | (1) |
%X
| 本地化的适当时间表示。 | 21:30:00 (en_US); 21:30:00 (de_DE) | (1) |
%%
|
字面的 '%' 字符。
| % |
为了方便起见,还包括了C89标准不需要的其他一些指示符。 这些参数都对应于 ISO 8601 日期值。
指示符 | 含意 | 示例 | 备注 |
---|---|---|---|
%G
|
带有世纪的 ISO 8601 年份,表示包含大部分 ISO 星期 (%V ) 的年份。
| 0001, 0002, …, 2013, 2014, …, 9998, 9999 | (8) |
%u
| 以十进制数显示的 ISO 8601 星期中的日序号,其中 1 表示星期一。 | 1, 2, …, 7 | |
%V
| 以十进制数显示的 ISO 8601 星期,以星期一作为每周的第一天。 第 01 周为包含 1 月 4 日的星期。 | 01, 02, …, 53 | (8), (9) |
%:z
|
±HH:MM[:SS[.ffffff]] 形式的 UTC 偏移量(如果是简单型对象则为空字符串)。
| (空), +00:00, -04:00, +10:30, +06:34:15, -03:07:12.345216 | (6) |
这些代码可能不是在所有平台上都可与 strftime()
方法配合使用。 ISO 8601 年份和 ISO 8601 星期指示符并不能与上面的年份和星期序号指示符相互替代。 调用 strptime()
时传入不完整或有歧义的 ISO 8601 指示符将引发 ValueError
。
对完整格式代码集的支持在不同平台上有所差异,因为 Python 要调用所在平台的 C 库的 strftime()
函数,而不同平台的差异是很常见的。 要查看你所用平台所支持的完整格式代码集,请参阅 strftime(3)) [https://manpages.debian.org/strftime(3)] 文档。 不同的平台在处理不支持的格式说明符方面也有差异。
Added in version 3.6: 增加了 %G
, %u
和 %V
。
Added in version 3.12: 增加了 %:z
。
技术细节
总体而言,d.strftime(fmt)
类似于 time
模块的 time.strftime(fmt, d.timetuple())
但是并非所有对象都支持 timetuple()
方法。
对于 datetime.strptime()
类方法,默认值为 1900-01-01T00:00:00.000
: 任何未在格式字符串中指定的部分都将从默认值中获取。 [4]
使用 datetime.strptime(date_string, format)
等价于:
- datetime(*(time.strptime(date_string, format)[0:6]))
除非格式中包含秒以下的部分或时区差值信息,它们在 datetime.strptime
中受支持但会被 time.strptime
所丢弃。
对于 time
对象,年、月、日的格式代码不应被使用,因为 time
对象没有这些值。 如果它们仍被使用,则年份将被替换为 1900 而月和日将被替换为 1。
对于 date
对象,时、分、秒和微秒的格式代码不应被使用,因为 date
对象没有这些值。 如果它们仍被使用,则都将被替换为 0。
出于相同的原因,对于包含当前区域设置字符集所无法表示的 Unicode 码位的格式字符串的处理方式也取决于具体平台。 在某些平台上这样的码位会不加修改地原样输出,而在其他平台上 strftime
则可能引发 UnicodeError
或只返回一个空字符串。
注释:
因为该格式依赖于当前语言区域,所以在假定输出值时应当仔细考虑。 字段顺序可能会有变化(例如 "month/day/year" 和 "day/month/year"),并且输出还可能包含非 ASCII 字符。
strptime()
方法能够解析整个 [1, 9999] 范围内的年份,但 < 1000 的年份必须加零填充为 4 位数字宽度。
在 3.2 版本发生变更: 在之前的版本中,strftime()
方法只限用于 >= 1900 的年份。
在 3.3 版本发生变更: 在 3.2 版中,strftime()
方法只限用于 >= 1000 的年份。
当与
strptime()
方法一起使用时,如果使用%I
指示符来解析时,则%p
指示符只会影响输出时字段。与
time
模块不同的是,datetime
模块不支持闰秒。当与
strptime()
方法一起使用时,%f
指示符可接受一至六个数码及左边的零填充。%f
是对 C 标准中格式字符集的扩展(但单独在 datetime 对象中实现,因此它总是可用)。对于简单型对象,
%z
,%:z
和%Z
格式代码会被替换为空字符串。
对于一个感知型对象而言:
%z
utcoffset()
会被转换为±HHMM[SS[.ffffff]]
形式的字符串,其中HH
为给出 UTC 时差的小时部分的 2 位数码字符串,MM
为给出 UTC 时差的分钟部分的 2 位数码字符串,SS
为给出 UTC 时差的秒部分的 2 位数码字符串,而ffffff
则为给出 UTC 时差的微秒部分的 6 位数码字符串。 当时差为整数秒时ffffff
部分将被省略,而当时差为整数分钟时ffffff
和SS
部分都将被省略。 举例来说,如果utcoffset()
返回timedelta(hours=-3, minutes=-30)
,则%z
会被替换为字符串'-0330'
。
在 3.7 版本发生变更: UTC 时差不再限制为一个整数分钟值。
在 3.7 版本发生变更: 当向 strptime()
方法提供 %z
指示符时,UTC 差值可以在时、分和秒之间使用冒号作为分隔符。 例如,'+01:00:00'
将被解读为一小时的差值。 此外,提供 'Z'
就相当于 '+00:00'
。
%:z
行为与
%z
相同,但在时,分和秒之间有冒号分隔符。%Z
- 在
strftime()
中,如果tzname()
返回None
则%Z
会被替换为一个空字符串;在其他情况下%Z
会被替换为该返回值,它必须为一个字符串。
strptime()
仅接受特定的 %Z
值:
-
你的机器的区域设置可以是 time.tzname
中的任何值
-
硬编码的值 UTC
和 GMT
这样生活在日本的人可用的值为 JST
, UTC
和 GMT
,但可能没有 EST
。 它将引发 ValueError
表示无效的值。
在 3.2 版本发生变更: 当提供 %z
指示符给 strptime()
方法时,将产生一个感知型 datetime
对象。 结果的 tzinfo
将被设为一个 timezone
实例。
当与
strptime()
方法一起使用时,%U
和%W
仅用于指定了星期值和日历年份 (%Y
) 的计算。类似于
%U
和%W
,%V
仅用于在strptime()
格式字符串中指定了星期值和 ISO 年份 (%G
) 的计算。 还要注意%G
和%Y
是不可互换的。当与
strptime()
方法一起使用时,前导的零在格式%d
,%m
,%H
,%I
,%M
,%S
,%j
,%U
,%W
和%V
中是可选的。 格式%y
则要求有前导的零。当使用
strptime()
解析月份和日期时,始终在格式字符串中包括年份。 如果你需要解析的值缺少年份,则添加一个显式的占位用闰年。 否则当你的代码遇到一个闰日时将引发异常因为解析器所使用的默认年份不是一个闰年。 用户会每隔四年碰到这个程序错误…
- >>> month_day = "02/29"
- >>> datetime.strptime(f"{month_day};1984", "%m/%d;%Y") # 没有闰年错误。
- datetime.datetime(1984, 2, 29, 0, 0)
Deprecated since version 3.13, will be removed in version 3.15: 使用包含不带年份的月份日期的格式字符串的 strptime()
调用现在将引发 DeprecationWarning
。 在 3.15 或更新的版本中我们可能将其修改为引发错误或将默认年从修改为一年闰年。 参见 gh-70647 [https://github.com/python/cpython/issues/70647]。
备注
[1] 就是说如果我们忽略相对论效应的话。
[2] 这与 Dershowitz 和 Reingold 所著 Calendrical Calculations 中“预期格列高利”历法的定义一致,它是适用于该书中所有运算的基础历法。 请参阅该书了解在预期格利高利历序列与许多其他历法系统之间进行转换的算法。
[3] 请参阅 R. H. van Gent 所著 ISO 8601 历法的数学指南 [https://web.archive.org/web/20220531051136/https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm] 以获取更完整的说明。
[4]
传入 datetime.strptime('Feb 29', '%b %d')
将导致错误,因为 1900 不是闰年。