datetime — 基本的日期和时间类型

源代码: Lib/datetime.py


datetime 模块提供了用于处理日期和时间的类。

虽然支持日期和时间算术运算,但实现的重点是高效的属性提取,以用于输出格式化和操作。

提示

跳转到 格式化代码

参见

模块 calendar

与日历相关的通用函数。

模块 time

时间的访问和转换。

模块 zoneinfo

表示 IANA 时区数据库的具体时区。

dateutil

具有扩展时区和解析支持的第三方库。

DateType

第三方库,它引入了不同的静态类型,例如,允许静态类型检查器区分 naive 和 aware 的 datetimes。

感知型和幼稚型对象

日期和时间对象可以分为“感知型 (aware)”或“幼稚型 (naive)”两类,取决于它们是否包含时区信息。

通过充分了解适用的算法和政治性时间调整,例如时区和夏令时信息,一个 感知型 (aware) 对象可以确定自身相对于其他感知型对象的位置。一个感知型对象代表一个确切的时间点,没有解释的余地。[1]

一个 幼稚型 (naive) 对象不包含足够的信息来明确地确定其相对于其他日期/时间对象的位置。幼稚型对象是表示协调世界时 (UTC)、本地时间还是其他时区的时间完全取决于程序,就像程序决定一个特定的数字是表示米、英里还是质量一样。幼稚型对象易于理解和使用,但代价是忽略了现实世界的某些方面。

对于需要感知型对象的应用程序,datetimetime 对象有一个可选的时区信息属性 tzinfo,可以将其设置为抽象 tzinfo 类的子类的实例。这些 tzinfo 对象捕获有关 UTC 时间偏移、时区名称以及夏令时是否有效的信息。

datetime 模块只提供了一个具体的 tzinfo 类,即 timezone 类。timezone 类可以表示与 UTC 有固定偏移量的简单时区,例如 UTC 本身或北美的 EST 和 EDT 时区。支持更深层次细节的时区取决于应用程序。世界各地的时间调整规则更多是政治性的而非理性的,而且经常变化,除了 UTC 之外,没有适用于每个应用的标准。

常量

datetime 模块导出以下常量:

datetime.MINYEAR

datedatetime 对象中允许的最小年份数。MINYEAR 是 1。

datetime.MAXYEAR

datedatetime 对象中允许的最大年份数。MAXYEAR 是 9999。

datetime.UTC

UTC 时区单例 datetime.timezone.utc 的别名。

在 3.11 版本中新增。

可用的类型

class datetime.date

一个理想化的幼稚型日期,假设当前的公历(格里高利历)一直有效,并且将永远有效。属性:yearmonthday

class datetime.time

一个理想化的时间,与任何特定的日期无关,假设每天恰好有 24*60*60 秒。(这里没有“闰秒”的概念。)属性:hourminutesecondmicrosecondtzinfo

class datetime.datetime

日期和时间的组合。属性:yearmonthdayhourminutesecondmicrosecondtzinfo

class datetime.timedelta

表示两个 datetimedate 实例之间差异的持续时间,分辨率可达微秒。

class datetime.tzinfo

时区信息对象的抽象基类。这些对象被 datetimetime 类用来提供可定制的时间调整概念(例如,考虑时区和/或夏令时)。

class datetime.timezone

一个实现了 tzinfo 抽象基类的类,表示与 UTC 的固定偏移量。

在 3.2 版本加入。

这些类型的对象是不可变的。

子类关系

object
    timedelta
    tzinfo
        timezone
    time
    date
        datetime

共同属性

datedatetimetimetimezone 类型共享这些共同特性:

  • 这些类型的对象是不可变的。

  • 这些类型的对象是可哈希的,这意味着它们可以用作字典的键。

  • 这些类型的对象通过 pickle 模块支持高效的序列化。

判断对象是感知型还是幼稚型

date 类型的对象总是幼稚型的。

timedatetime 类型的对象可能是感知型或幼稚型。

一个 datetime 对象 d 是感知型的,如果以下两个条件都成立:

  1. d.tzinfo 不为 None

  2. d.tzinfo.utcoffset(d) 不返回 None

否则,d 是幼稚型的。

一个 time 对象 t 是感知型的,如果以下两个条件都成立:

  1. t.tzinfo 不为 None

  2. t.tzinfo.utcoffset(None) 不返回 None

否则,t 是幼稚型的。

感知型和幼稚型之间的区别不适用于 timedelta 对象。

timedelta 对象

一个 timedelta 对象表示一个持续时间,即两个 datetimedate 实例之间的差值。

class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

所有参数都是可选的,默认为 0。参数可以是整数或浮点数,可以是正数或负数。

内部只存储 dayssecondsmicroseconds。参数会转换为这些单位:

  • 1 毫秒转换为 1000 微秒。

  • 1 分钟转换为 60 秒。

  • 1 小时转换为 3600 秒。

  • 1 周转换为 7 天。

然后对天、秒和微秒进行标准化,以使表示唯一,其中:

  • 0 <= microseconds < 1000000

  • 0 <= seconds < 3600*24(一天中的秒数)

  • -999999999 <= days <= 999999999

以下示例说明了除 dayssecondsmicroseconds 之外的任何参数是如何被“合并”并标准化为这三个结果属性的:

>>> from datetime import timedelta
>>> delta = timedelta(
...     days=50,
...     seconds=27,
...     microseconds=10,
...     milliseconds=29000,
...     minutes=5,
...     hours=8,
...     weeks=2
... )
>>> # Only days, seconds, and microseconds remain
>>> delta
datetime.timedelta(days=64, seconds=29156, microseconds=10)

如果任何参数是浮点数并且存在小数微秒,则来自所有参数的小数微秒会被合并,它们的和会使用四舍六入五成双的规则舍入到最近的微秒。如果没有参数是浮点数,转换和标准化过程是精确的(不会丢失信息)。

如果标准化的天数值超出了指定范围,则会引发 OverflowError

请注意,负值的标准化起初可能令人惊讶。例如:

>>> from datetime import timedelta
>>> d = timedelta(microseconds=-1)
>>> (d.days, d.seconds, d.microseconds)
(-1, 86399, 999999)

由于 timedelta 对象的字符串表示形式可能会令人困惑,请使用以下方法生成更易读的格式:

>>> def pretty_timedelta(td):
...     if td.days >= 0:
...         return str(td)
...     return f'-({-td!s})'
...
>>> d = timedelta(hours=-1)
>>> str(d)  # not human-friendly
'-1 day, 23:00:00'
>>> pretty_timedelta(d)
'-(1:00:00)'

类属性:

timedelta.min

最负的 timedelta 对象,timedelta(-999999999)

timedelta.max

最正的 timedelta 对象,timedelta(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999)

timedelta.resolution

非相等 timedelta 对象之间可能的最小差值,timedelta(microseconds=1)

注意,由于标准化,timedelta.max 大于 -timedelta.min-timedelta.max 不能表示为 timedelta 对象。

实例属性(只读):

timedelta.days

介于 -999,999,999 和 999,999,999 之间(含)。

timedelta.seconds

介于 0 和 86,399 之间(含)。

注意

一个常见的错误是,代码在实际上想获取 total_seconds() 值时,无意中使用了这个属性:

>>> from datetime import timedelta
>>> duration = timedelta(seconds=11235813)
>>> duration.days, duration.seconds
(130, 3813)
>>> duration.total_seconds()
11235813.0
timedelta.microseconds

介于 0 和 999,999 之间(含)。

支持的操作:

操作

结果

t1 = t2 + t3

t2t3 的和。之后 t1 - t2 == t3t1 - t3 == t2 均为真。(1)

t1 = t2 - t3

t2t3 的差。之后 t1 == t2 - t3t2 == t1 + t3 均为真。(1)(6)

t1 = t2 * i t1 = i * t2

时间差乘以一个整数。之后,当 i != 0 时,t1 // i == t2 为真。

通常,t1  * i == t1 * (i-1) + t1 为真。(1)

t1 = t2 * f t1 = f * t2

时间差乘以一个浮点数。结果会使用四舍六入五成双的规则舍入到 timedelta.resolution 的最近倍数。

f = t2 / t3

总持续时间 t2 除以时间间隔单位 t3 的除法 (3)。返回一个 float 对象。

t1 = t2 / f t1 = t2 / i

时间差除以一个浮点数或整数。结果会使用四舍六入五成双的规则舍入到 timedelta.resolution 的最近倍数。

t1 = t2 // it1 = t2 // t3

计算向下取整的结果,并丢弃余数(如果有的话)。在第二种情况下,返回一个整数。(3)

t1 = t2 % t3

余数以 timedelta 对象的形式计算。(3)

q, r = divmod(t1, t2)

计算商和余数:q = t1 // t2 (3) 和 r = t1 % t2q 是一个整数,r 是一个 timedelta 对象。

+t1

返回一个值相同的 timedelta 对象。(2)

-t1

等价于 timedelta(-t1.days, -t1.seconds, -t1.microseconds),以及 t1 * -1。(1)(4)

abs(t)

t.days >= 0 时,等价于 +t;当 t.days < 0 时,等价于 -t。(2)

str(t)

返回一个格式为 [D day[s], ][H]H:MM:SS[.UUUUUU] 的字符串,当 t 为负时,D 为负数。(5)

repr(t)

返回一个 timedelta 对象的字符串表示形式,该表示形式是一个带有规范属性值的构造函数调用。

备注

  1. 这是精确的,但可能溢出。

  2. 这是精确的,不会溢出。

  3. 除以零会引发 ZeroDivisionError

  4. -timedelta.max 不能表示为一个 timedelta 对象。

  5. timedelta 对象的字符串表示形式与其内部表示类似地进行标准化。这导致负的 timedelta 出现一些不寻常的结果。例如:

    >>> timedelta(hours=-5)
    datetime.timedelta(days=-1, seconds=68400)
    >>> print(_)
    -1 day, 19:00:00
    
  6. 表达式 t2 - t3 将总是等于表达式 t2 + (-t3),除非 t3 等于 timedelta.max;在这种情况下,前者会产生一个结果,而后者会溢出。

除了上面列出的操作外,timedelta 对象还支持与 datedatetime 对象的某些加法和减法运算(见下文)。

在 3.2 版本发生变更: 现在支持一个 timedelta 对象与另一个 timedelta 对象的整除和真除法,以及取余运算和 divmod() 函数。现在支持一个 timedelta 对象与一个 float 对象的真除法和乘法。

timedelta 对象支持相等和顺序比较。

在布尔上下文中,一个 timedelta 对象当且仅当它不等于 timedelta(0) 时被认为是真的。

实例方法:

timedelta.total_seconds()

返回持续时间中包含的总秒数。等价于 td / timedelta(seconds=1)。对于除秒之外的时间间隔单位,直接使用除法形式(例如 td / timedelta(microseconds=1))。

注意,对于非常大的时间间隔(在大多数平台上大于 270 年),此方法将失去微秒精度。

在 3.2 版本加入。

用法示例:timedelta

一个额外的标准化示例:

>>> # Components of another_year add up to exactly 365 days
>>> from datetime import timedelta
>>> year = timedelta(days=365)
>>> another_year = timedelta(weeks=40, days=84, hours=23,
...                          minutes=50, seconds=600)
>>> year == another_year
True
>>> year.total_seconds()
31536000.0

timedelta 算术运算示例:

>>> from datetime import timedelta
>>> year = timedelta(days=365)
>>> ten_years = 10 * year
>>> ten_years
datetime.timedelta(days=3650)
>>> ten_years.days // 365
10
>>> nine_years = ten_years - year
>>> nine_years
datetime.timedelta(days=3285)
>>> three_years = nine_years // 3
>>> three_years, three_years.days // 365
(datetime.timedelta(days=1095), 3)

date 对象

一个 date 对象表示一个理想化日历中的日期(年、月、日),即当前的公历(格里高利历)向两个方向无限延伸。

公元 1 年 1 月 1 日被称为第 1 天,公元 1 年 1 月 2 日被称为第 2 天,以此类推。[2]

class datetime.date(year, month, day)

所有参数都是必需的。参数必须是整数,且在以下范围内:

  • MINYEAR <= year <= MAXYEAR

  • 1 <= month <= 12

  • 1 <= day <= 给定月份和年份的天数

如果给定的参数超出这些范围,会引发 ValueError

其他构造函数,均为类方法:

classmethod date.today()

返回当前的本地日期。

这等价于 date.fromtimestamp(time.time())

classmethod date.fromtimestamp(timestamp)

返回与 POSIX 时间戳对应的本地日期,例如 time.time() 返回的时间戳。

如果时间戳超出了平台 C 语言 localtime() 函数支持的值范围,可能会引发 OverflowError;如果 localtime() 失败,则会引发 OSError。通常,这被限制在 1970 年到 2038 年之间。请注意,在非 POSIX 系统中,如果时间戳概念包含闰秒,fromtimestamp() 会忽略闰秒。

在 3.3 版本发生变更: 如果时间戳超出了平台 C 语言 localtime() 函数支持的值范围,则引发 OverflowError 而非 ValueError。如果 localtime() 失败,则引发 OSError 而非 ValueError

classmethod date.fromordinal(ordinal)

返回对应于前推公历序数的日期,其中公元 1 年 1 月 1 日的序数为 1。

除非 1 <= ordinal <= date.max.toordinal(),否则会引发 ValueError。对于任何日期 ddate.fromordinal(d.toordinal()) == d

classmethod date.fromisoformat(date_string)

返回一个与 date_string 对应的 date 对象,该字符串以任何有效的 ISO 8601 格式给出,但有以下例外:

  1. 目前不支持降低精度的日期(YYYY-MM, YYYY)。

  2. 目前不支持扩展日期表示法(±YYYYYY-MM-DD)。

  3. 目前不支持序数日期(YYYY-OOO)。

示例:

>>> from datetime import date
>>> date.fromisoformat('2019-12-04')
datetime.date(2019, 12, 4)
>>> date.fromisoformat('20191204')
datetime.date(2019, 12, 4)
>>> date.fromisoformat('2021-W01-1')
datetime.date(2021, 1, 4)

在 3.7 版本加入。

在 3.11 版本发生变更: 以前,此方法仅支持 YYYY-MM-DD 格式。

classmethod date.fromisocalendar(year, week, day)

返回一个与由年、周和日指定的 ISO 日历日期相对应的 date。这是 date.isocalendar() 函数的逆操作。

在 3.8 版本加入。

classmethod date.strptime(date_string, format)

返回一个与 date_string 对应的 date,根据 format 进行解析。这等价于:

date(*(time.strptime(date_string, format)[0:3]))

如果 date_string 和 format 无法被 time.strptime() 解析,或者如果它返回的值不是一个时间元组,则会引发 ValueError。另请参见 strftime() 和 strptime() 的行为date.fromisoformat()

备注

如果 format 指定了月份中的某一天但没有年份,会发出一个 DeprecationWarning。这是为了避免在寻求仅解析月份和日期的代码中出现四年一次的闰年错误,因为在格式中缺少年份时使用的默认年份不是闰年。从 Python 3.15 开始,这样的 format 值可能会引发错误。解决方法是在您的 format 中始终包含年份。如果解析的 date_string 值没有年份,请在解析前明确添加一个闰年:

>>> from datetime import date
>>> date_string = "02/29"
>>> when = date.strptime(f"{date_string};1984", "%m/%d;%Y")  # Avoids leap year bug.
>>> when.strftime("%B %d")
'February 29'

在 3.14 版本加入。

类属性:

date.min

最早的可表示日期,date(MINYEAR, 1, 1)

date.max

最晚的可表示日期,date(MAXYEAR, 12, 31)

date.resolution

非相等日期对象之间可能的最小差值,timedelta(days=1)

实例属性(只读):

date.year

介于 MINYEARMAXYEAR 之间(含)。

date.month

介于 1 和 12 之间(含)。

date.day

介于 1 和给定年份给定月份的天数之间。

支持的操作:

操作

结果

date2 = date1 + timedelta

date2 将是 date1 之后 timedelta.days 天的日期。(1)

date2 = date1 - timedelta

计算 date2,使得 date2 + timedelta == date1。(2)

timedelta = date1 - date2

(3)

date1 == date2
date1 != date2

相等性比较。(4)

date1 < date2
date1 > date2
date1 <= date2
date1 >= date2

顺序比较。(5)

备注

  1. 如果 timedelta.days > 0date2 会在时间上向前移动;如果 timedelta.days < 0,则向后移动。之后 date2 - date1 == timedelta.daystimedelta.secondstimedelta.microseconds 被忽略。如果 date2.year 小于 MINYEAR 或大于 MAXYEAR,则会引发 OverflowError

  2. timedelta.secondstimedelta.microseconds 被忽略。

  3. 这是精确的,不会溢出。timedelta.secondstimedelta.microseconds 为 0,并且之后 date2 + timedelta == date1

  4. 如果两个 date 对象表示相同的日期,则它们相等。

    datetime 实例的 date 对象永远不等于 datetime 对象,即使它们表示相同的日期。

  5. date1 在时间上先于 date2 时,date1 被认为小于 date2。换句话说,date1 < date2 当且仅当 date1.toordinal() < date2.toordinal()

    datetime 实例的 date 对象与 datetime 对象之间的顺序比较会引发 TypeError

在 3.13 版本发生变更: datetime 对象与非 datetime 子类的 date 子类的实例之间的比较,不再将后者转换为 date,从而忽略时间部分和时区。可以通过在子类中重写特殊的比较方法来更改默认行为。

在布尔上下文中,所有 date 对象都被认为是真的。

实例方法:

date.replace(year=self.year, month=self.month, day=self.day)

返回一个具有相同值的新 date 对象,但更新了指定的参数。

示例

>>> from datetime import date
>>> d = date(2002, 12, 31)
>>> d.replace(day=26)
datetime.date(2002, 12, 26)

通用函数 copy.replace() 也支持 date 对象。

date.timetuple()

返回一个 time.struct_time,类似于 time.localtime() 返回的类型。

小时、分钟和秒为 0,DST 标志为 -1。

d.timetuple() 等价于:

time.struct_time((d.year, d.month, d.day, 0, 0, 0, d.weekday(), yday, -1))

其中 yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1 是当前年份中的天数,1 月 1 日为 1。

date.toordinal()

返回日期的前推公历序数,其中公元 1 年 1 月 1 日的序数为 1。对于任何 date 对象 ddate.fromordinal(d.toordinal()) == d

date.weekday()

以整数形式返回星期几,其中星期一为 0,星期日为 6。例如,date(2002, 12, 4).weekday() == 2,表示星期三。另请参见 isoweekday()

date.isoweekday()

以整数形式返回星期几,其中星期一为 1,星期日为 7。例如,date(2002, 12, 4).isoweekday() == 3,表示星期三。另请参见 weekday()isocalendar()

date.isocalendar()

返回一个包含三个组件的命名元组对象:yearweekweekday

ISO 日历是公历(格里高利历)的一种广泛使用的变体。[3]

ISO 年由 52 或 53 个完整周组成,每周从星期一开始,到星期日结束。一个 ISO 年的第一周是一年中包含星期四的第一个(公历)日历周。这被称为第 1 周,该星期四的 ISO 年与其公历年份相同。

例如,2004 年从星期四开始,所以 ISO 2004 年的第一周从 2003 年 12 月 29 日星期一开始,到 2004 年 1 月 4 日星期日结束:

>>> from datetime import date
>>> date(2003, 12, 29).isocalendar()
datetime.IsoCalendarDate(year=2004, week=1, weekday=1)
>>> date(2004, 1, 4).isocalendar()
datetime.IsoCalendarDate(year=2004, week=1, weekday=7)

在 3.9 版本发生变更: 结果从元组更改为命名元组

date.isoformat()

返回一个表示日期的字符串,格式为 ISO 8601,YYYY-MM-DD

>>> from datetime import date
>>> date(2002, 12, 4).isoformat()
'2002-12-04'
date.__str__()

对于一个日期 dstr(d) 等价于 d.isoformat()

date.ctime()

返回一个表示日期的字符串:

>>> from datetime import date
>>> date(2002, 12, 4).ctime()
'Wed Dec  4 00:00:00 2002'

d.ctime() 等价于:

time.ctime(time.mktime(d.timetuple()))

在本地 C 语言 ctime() 函数(time.ctime() 会调用,但 date.ctime() 不会调用)符合 C 标准的平台上。

date.strftime(format)

返回一个表示日期的字符串,由显式格式字符串控制。引用小时、分钟或秒的格式代码将看到 0 值。另请参见 strftime() 和 strptime() 的行为date.isoformat()

date.__format__(format)

date.strftime() 相同。这使得在格式化字符串字面量和使用 str.format() 时可以为 date 对象指定格式字符串。另请参见 strftime() 和 strptime() 的行为date.isoformat()

用法示例: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) # 730920th day after 1. 1. 0001
>>> d
datetime.date(2002, 3, 11)

>>> # Methods related to formatting string output
>>> 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.'

>>> # Methods for to extracting 'components' under different calendars
>>> t = d.timetuple()
>>> for i in t:
...     print(i)
2002                # year
3                   # month
11                  # day
0
0
0
0                   # weekday (0 = Monday)
70                  # 70th day in the year
-1
>>> ic = d.isocalendar()
>>> for i in ic:
...     print(i)
2002                # ISO year
11                  # ISO week number
1                   # ISO day number ( 1 = Monday )

>>> # A date object is immutable; all operations produce a new object
>>> 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)

yearmonthday 参数是必需的。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()

返回当前的本地日期和时间,tzinfoNone

等价于:

datetime.fromtimestamp(time.time())

另请参见 now()fromtimestamp()

此方法在功能上等同于 now(),但没有 tz 参数。

classmethod datetime.now(tz=None)

返回当前的本地日期和时间。

如果可选参数 tzNone 或未指定,这类似于 today(),但如果可能,它提供的精度比通过 time.time() 时间戳获得的精度更高(例如,在提供 C 语言 gettimeofday() 函数的平台上可能如此)。

如果 tz 不为 None,它必须是 tzinfo 子类的实例,并且当前的日期和时间会转换为 tz 的时区。

此函数优于 today()utcnow()

备注

后续对 datetime.now() 的调用可能返回相同的时间点,具体取决于底层时钟的精度。

classmethod datetime.utcnow()

返回当前的 UTC 日期和时间,tzinfoNone

这类似于 now(),但返回的是当前的 UTC 日期和时间,作为一个幼稚型 datetime 对象。可以通过调用 datetime.now(timezone.utc) 来获得一个感知型的当前 UTC 日期时间。另请参见 now()

警告

由于幼稚型 datetime 对象被许多 datetime 方法视作本地时间,因此推荐使用感知型 datetime 来表示 UTC 时间。因此,创建表示当前 UTC 时间的对象的推荐方法是调用 datetime.now(timezone.utc)

自 3.12 版本起不推荐使用: 请改用带 UTCdatetime.now()

classmethod datetime.fromtimestamp(timestamp, tz=None)

返回与 POSIX 时间戳对应的本地日期和时间,例如 time.time() 返回的时间戳。如果可选参数 tzNone 或未指定,时间戳会转换为平台的本地日期和时间,返回的 datetime 对象是幼稚型的。

如果 tz 不为 None,则它必须是 tzinfo 子类的实例,并且时间戳会转换为 tz 所在的时区。

如果时间戳超出了平台 C 的 localtime()gmtime() 函数所支持的值范围,fromtimestamp() 可能会引发 OverflowError;如果 localtime()gmtime() 失败,则会引发 OSError。这个范围通常被限制在 1970 年到 2038 年之间。请注意,在那些将闰秒包含在其时间戳概念中的非 POSIX 系统上,闰秒会被 fromtimestamp() 忽略,因此可能出现两个相差一秒的时间戳产生相同的 datetime 对象。此方法优于 utcfromtimestamp()

在 3.3 版更改: 如果时间戳超出了平台 C 的 localtime()gmtime() 函数支持的值范围,则会引发 OverflowError 而不是 ValueError。如果 localtime()gmtime() 失败,则会引发 OSError 而不是 ValueError

在 3.6 版更改: fromtimestamp() 可能会返回 fold 属性设置为 1 的实例。

classmethod datetime.utcfromtimestamp(timestamp)

返回与 POSIX 时间戳对应的 UTC datetime,其中 tzinfoNone。(结果对象是朴素的。)

如果时间戳超出了平台 C 的 gmtime() 函数所支持的值范围,此方法可能会引发 OverflowError;如果 gmtime() 失败,则会引发 OSError。这个范围通常被限制在 1970 年到 2038 年之间。

要获取一个感知的 datetime 对象,请调用 fromtimestamp()

datetime.fromtimestamp(timestamp, timezone.utc)

在遵循 POSIX 标准的平台上,它等价于以下表达式:

datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp)

不同之处在于后者公式总是支持完整的年份范围:从 MINYEARMAXYEAR(包含边界)。

警告

由于许多 datetime 方法将朴素的 datetime 对象视为本地时间,因此推荐使用感知的 datetime 对象来表示 UTC 时间。因此,创建代表 UTC 特定时间戳的对象的推荐方法是调用 datetime.fromtimestamp(timestamp, tz=timezone.utc)

在 3.3 版更改: 如果时间戳超出了平台 C 的 gmtime() 函数支持的值范围,则会引发 OverflowError 而不是 ValueError。如果 gmtime() 失败,则会引发 OSError 而不是 ValueError

自 3.12 版本起弃用: 请改用带 UTCdatetime.fromtimestamp()

classmethod datetime.fromordinal(ordinal)

返回对应于预期公历序数的 datetime,其中第 1 年的 1 月 1 日的序数为 1。除非 1 <= ordinal <= datetime.max.toordinal(),否则会引发 ValueError。结果的小时、分钟、秒和微秒都为 0,且 tzinfoNone

classmethod datetime.combine(date, time, tzinfo=time.tzinfo)

返回一个新的 datetime 对象,其日期部分等于给定的 date 对象的日期部分,时间部分等于给定的 time 对象的时间部分。如果提供了 tzinfo 参数,其值将用于设置结果的 tzinfo 属性,否则将使用 time 参数的 tzinfo 属性。如果 date 参数是 datetime 对象,其时间部分和 tzinfo 属性将被忽略。

对于任何 datetime 对象 dd == datetime.combine(d.date(), d.time(), d.tzinfo) 成立。

在 3.6 版更改: 添加了 tzinfo 参数。

classmethod datetime.fromisoformat(date_string)

返回与任何有效的 ISO 8601 格式的 date_string 对应的 datetime,但有以下例外:

  1. 时区偏移量可以有小数秒。

  2. T 分隔符可以被任何单个 unicode 字符替换。

  3. 不支持小数小时和分钟。

  4. 目前不支持降低精度的日期(YYYY-MM, YYYY)。

  5. 目前不支持扩展日期表示法(±YYYYYY-MM-DD)。

  6. 目前不支持序数日期(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)))

在 3.7 版本加入。

在 3.11 版更改: 以前,此方法只支持 date.isoformat()datetime.isoformat() 可以生成的格式。

classmethod datetime.fromisocalendar(year, week, day)

返回与由年、周和日指定的 ISO 日历日期相对应的 datetime。datetime 的非日期部分将使用其正常的默认值填充。这是 datetime.isocalendar() 函数的逆操作。

在 3.8 版本加入。

classmethod datetime.strptime(date_string, format)

返回一个根据 format 解析 date_string 后得到的 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.year

介于 MINYEARMAXYEAR 之间(含)。

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

传递给 datetime 构造函数的 tzinfo 参数的对象,如果没有传递则为 None

datetime.fold

[0, 1] 范围内。用于在重复的时间区间内消除时钟时间的歧义。(当夏令时结束时钟回拨,或当前时区的 UTC 偏移因政治原因减少时,会出现重复的时间区间。)值 0 和 1 分别表示具有相同墙上时钟时间表示的两个时刻中较早和较晚的一个。

在 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)

  1. datetime2 是从 datetime1 移除了 timedelta 持续时间后的结果,如果 timedelta.days > 0 则时间向前移动,如果 timedelta.days < 0 则向后移动。结果具有与输入 datetime 相同的 tzinfo 属性,并且之后 datetime2 - datetime1 == timedelta。如果 datetime2.year 会小于 MINYEAR 或大于 MAXYEAR,则会引发 OverflowError。请注意,即使输入是感知的对象,也不会进行时区调整。

  2. 计算 datetime2 使得 datetime2 + timedelta == datetime1。与加法一样,结果具有与输入 datetime 相同的 tzinfo 属性,并且即使输入是感知的,也不会进行时区调整。

  3. 从一个 datetime 减去另一个 datetime 的操作仅在两个操作数都是朴素的,或都是感知的情况下才被定义。如果一个是感知的而另一个是朴素的,则会引发 TypeError

    如果两者都是朴素的,或者两者都是感知的且具有相同的 tzinfo 属性,那么 tzinfo 属性将被忽略,结果是一个 timedelta 对象 t,使得 datetime2 + t == datetime1。在这种情况下不进行时区调整。

    如果两者都是感知的且具有不同的 tzinfo 属性,a-b 的行为就好像 ab 首先被转换成了朴素的 UTC datetime。结果是 (a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset()),但实现上不会溢出。

  4. datetime 对象如果表示相同的日期和时间(考虑到时区),则它们是相等的。

    朴素和感知的 datetime 对象永远不相等。

    如果两个比较对象都是感知的,并且具有相同的 tzinfo 属性,那么 tzinfofold 属性将被忽略,只比较基础的 datetime。如果两个比较对象都是感知的,但具有不同的 tzinfo 属性,比较的行为就好像比较对象首先被转换成了 UTC datetime,但实现上不会溢出。处于重复时间区间内的 datetime 实例永远不等于其他时区中的 datetime 实例。

  5. datetime1 在时间上早于 datetime2 时(考虑到时区),认为 datetime1 小于 datetime2

    在朴素和感知的 datetime 对象之间进行顺序比较会引发 TypeError

    如果两个比较对象都是感知的,并且具有相同的 tzinfo 属性,那么 tzinfofold 属性将被忽略,只比较基础的 datetime。如果两个比较对象都是感知的,但具有不同的 tzinfo 属性,比较的行为就好像比较对象首先被转换成了 UTC datetime,但实现上不会溢出。

在 3.3 版更改: 感知和朴素的 datetime 实例之间的相等性比较不再引发 TypeError

在 3.13 版本发生变更: datetime 对象与非 datetime 子类的 date 子类的实例之间的比较,不再将后者转换为 date,从而忽略时间部分和时区。可以通过在子类中重写特殊的比较方法来更改默认行为。

实例方法:

datetime.date()

返回具有相同年、月、日的 date 对象。

datetime.time()

返回具有相同小时、分钟、秒、微秒和 fold 的 time 对象。tzinfoNone。另请参见 timetz() 方法。

在 3.6 版更改: fold 值被复制到返回的 time 对象中。

datetime.timetz()

返回具有相同小时、分钟、秒、微秒、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 属性 tzdatetime 对象,并调整日期和时间数据,使结果与 self 表示的 UTC 时间相同,但在 tz 的本地时间中。

如果提供了 tz,它必须是 tzinfo 子类的实例,并且其 utcoffset()dst() 方法不能返回 None。如果 self 是朴素的,则假定它表示系统时区中的时间。

如果不带参数调用(或使用 tz=None),则假定目标时区为系统本地时区。转换后的 datetime 实例的 .tzinfo 属性将被设置为一个 timezone 的实例,其时区名称和偏移量从操作系统获取。

如果 self.tzinfotz,则 self.astimezone(tz) 等于 self:不执行日期或时间数据的调整。否则,结果是时区 tz 中的本地时间,表示与 self 相同的 UTC 时间:在 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
    # Convert self to UTC, and attach the new timezone object.
    utc = (self - self.utcoffset()).replace(tzinfo=tz)
    # Convert from UTC to tz's local time.
    return tz.fromutc(utc)

在 3.3 版更改: tz 现在可以省略。

在 3.6 版更改: astimezone() 方法现在可以在被假定为表示系统本地时间的朴素实例上调用。

datetime.utcoffset()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.utcoffset(self),如果后者没有返回 None 或一个大小小于一天的 timedelta 对象,则引发异常。

在 3.7 版更改: UTC 偏移量不再限制为整数分钟。

datetime.dst()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(self),如果后者没有返回 None 或一个大小小于一天的 timedelta 对象,则引发异常。

在 3.7 版更改: DST 偏移量不再限制为整数分钟。

datetime.tzname()

如果 tzinfoNone,则返回 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() 方法设置:如果 tzinfoNonedst() 返回 None,则 tm_isdst 设置为 -1;否则如果 dst() 返回一个非零值,tm_isdst 设置为 1;否则 tm_isdst 设置为 0。

datetime.utctimetuple()

如果 datetime 实例 d 是朴素的,这与 d.timetuple() 相同,只是无论 d.dst() 返回什么,tm_isdst 都会被强制为 0。UTC 时间永远不会有夏令时。

如果 d 是感知的,d 会通过减去 d.utcoffset() 被标准化为 UTC 时间,并返回标准化时间的 time.struct_timetm_isdst 被强制为 0。请注意,如果 d.yearMINYEARMAXYEAR 并且 UTC 调整跨越了年份边界,可能会引发 OverflowError

警告

因为许多 datetime 方法将朴素的 datetime 对象视为本地时间,所以推荐使用感知的 datetime 来表示 UTC 时间;因此,使用 datetime.utctimetuple() 可能会产生误导性的结果。如果你有一个表示 UTC 的朴素 datetime,使用 datetime.replace(tzinfo=timezone.utc) 使其变为感知的,然后你就可以使用 datetime.timetuple() 了。

datetime.toordinal()

返回日期的预期公历序数。与 self.date().toordinal() 相同。

datetime.timestamp()

返回与 datetime 实例对应的 POSIX 时间戳。返回值是一个 float,类似于 time.time() 返回的值。

朴素的 datetime 实例被假定为表示本地时间,此方法依赖于平台 C 的 mktime() 函数来执行转换。由于 datetime 在许多平台上支持的值范围比 mktime() 更广,对于遥远的过去或未来的时间,此方法可能会引发 OverflowErrorOSError

对于感知的 datetime 实例,返回值的计算方式为:

(dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()

在 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()

返回一个包含三个组件的命名元组yearweekweekday。与 self.date().isocalendar() 相同。

datetime.isoformat(sep='T', timespec='auto')

返回一个表示 ISO 8601 格式的日期和时间的字符串:

如果 utcoffset() 不返回 None,则会追加一个字符串,给出 UTC 偏移量:

  • YYYY-MM-DDTHH:MM:SS.ffffff+HH:MM[:SS[.ffffff]],如果 microsecond 不为 0

  • YYYY-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

  • 'minutes':以 HH:MM 格式包含 hourminute

  • 'seconds':以 HH:MM:SS 格式包含 hourminutesecond

  • '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 实例 dstr(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() 函数(time.ctime() 会调用,但 datetime.ctime() 不会调用)符合 C 标准的平台上。

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

>>> # Using datetime.combine()
>>> d = date(2005, 7, 14)
>>> t = time(12, 30)
>>> datetime.combine(d, t)
datetime.datetime(2005, 7, 14, 12, 30)

>>> # Using 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)

>>> # Using datetime.strptime()
>>> dt = datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
>>> dt
datetime.datetime(2006, 11, 21, 16, 30)

>>> # Using datetime.timetuple() to get tuple of all attributes
>>> tt = dt.timetuple()
>>> for it in tt:
...     print(it)
...
2006    # year
11      # month
21      # day
16      # hour
30      # minute
0       # second
1       # weekday (0 = Monday)
325     # number of days since 1st January
-1      # dst - method tzinfo.dst() returned None

>>> # Date in ISO format
>>> ic = dt.isocalendar()
>>> for it in ic:
...     print(it)
...
2006    # ISO year
47      # ISO week
2       # ISO weekday

>>> # Formatting a datetime
>>> 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 子类,用于捕获阿富汗喀布尔的时区信息,该地区在 1945 年之前使用 UTC+4,之后使用 UTC+4:30:

from datetime import timedelta, datetime, tzinfo, timezone

class KabulTz(tzinfo):
    # Kabul used +4 until 1945, when they moved to +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):
            # An ambiguous ("imaginary") half-hour range representing
            # a 'fold' in time due to the shift from +4 to +4:30.
            # If dt falls in the imaginary range, use fold to decide how
            # to resolve. See PEP495.
            return timedelta(hours=4, minutes=(30 if dt.fold else 0))
        else:
            return timedelta(hours=4, minutes=30)

    def fromutc(self, dt):
        # Follow same validations as in 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")

        # A custom implementation is required for fromutc as
        # the input to this function is a datetime with utc values
        # but with a tzinfo set to self.
        # See datetime.astimezone or 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):
        # Kabul does not observe daylight saving time.
        return timedelta(0)

    def tzname(self, dt):
        if dt >= self.UTC_MOVE_DATE:
            return "+04:30"
        return "+04"

使用上面的 KabulTz

>>> tz1 = KabulTz()

>>> # Datetime before the change
>>> dt1 = datetime(1900, 11, 21, 16, 30, tzinfo=tz1)
>>> print(dt1.utcoffset())
4:00:00

>>> # Datetime after the change
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=tz1)
>>> print(dt2.utcoffset())
4:30:00

>>> # Convert datetime to another time zone
>>> 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。除了 tzinfo 默认为 None 之外,所有参数都默认为 0。

类属性:

time.min

可表示的最早的 time,即 time(0, 0, 0, 0)

time.max

可表示的最晚的 time,即 time(23, 59, 59, 999999)

time.resolution

两个不相等的 time 对象之间可能的最小差值,即 timedelta(microseconds=1),但请注意,不支持对 time 对象进行算术运算。

实例属性(只读):

time.hour

range(24) 范围内。

time.minute

range(60) 范围内。

time.second

range(60) 范围内。

time.microsecond

range(1000000) 范围内。

time.tzinfo

传递给 time 构造函数的 tzinfo 参数的对象,如果没有传递则为 None

time.fold

[0, 1] 范围内。用于在重复的时间区间内消除时钟时间的歧义。(当夏令时结束时钟回拨,或当前时区的 UTC 偏移因政治原因减少时,会出现重复的时间区间。)值 0 和 1 分别表示具有相同墙上时钟时间表示的两个时刻中较早和较晚的一个。

在 3.6 版本加入。

time 对象支持相等性和顺序比较,当 a 在时间上早于 b 时,认为 a 小于 b

简单 time 对象和感知 time 对象永远不相等。 简单和感知 time 对象之间的大小比较会引发 TypeError

如果两个比较对象都是感知的,并且具有相同的 tzinfo 属性,则会忽略 tzinfofold 属性,并比较基础时间。如果两个比较对象都是感知的,但具有不同的 tzinfo 属性,则首先通过减去它们的 UTC 偏移量(从 self.utcoffset() 获得)来调整比较对象。

在 3.3 版更改: 感知和简单 time 实例之间的相等性比较不会引发 TypeError

在布尔上下文中,time 对象总是被视为真值。

在 3.5 版更改: 在 Python 3.5 之前,如果一个 time 对象代表 UTC 的午夜,则它被认为是假值。此行为被认为是晦涩且容易出错的,并在 Python 3.5 中被移除。有关完整详细信息,请参阅 bpo-13936

其他构造器

classmethod time.fromisoformat(time_string)

返回一个与 time_string 对应的 time 对象,该字符串可以是任何有效的 ISO 8601 格式,但有以下例外:

  1. 时区偏移量可以有小数秒。

  2. 前导的 T(在日期和时间可能存在歧义的情况下通常是必需的)不是必需的。

  3. 小数秒可以有任意数量的数字(超过 6 位的将被截断)。

  4. 不支持小数小时和分钟。

示例:

>>> 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)

在 3.7 版本加入。

在 3.11 版更改: 以前,此方法仅支持 time.isoformat() 可以发出的格式。

classmethod time.strptime(date_string, format)

返回一个与 date_string 相对应的 time 对象,根据 format 进行解析。

如果 format 不包含微秒或时区信息,这等同于:

time(*(time.strptime(date_string, format)[3:6]))

如果 date_stringformat 无法被 time.strptime() 解析,或者如果它返回的值不是时间元组,则会引发 ValueError。另请参阅 strftime() 和 strptime() 的行为time.fromisoformat()

在 3.14 版本加入。

实例方法:

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 格式表示时间的字符串,以下格式之一:

可选参数 timespec 指定要包含的时间的附加组件数量(默认为 'auto')。它可以是以下之一:

  • 'auto': 如果 microsecond 为 0,则与 'seconds' 相同,否则与 'microseconds' 相同。

  • 'hours': 以两位数的 HH 格式包含 hour

  • 'minutes': 以 HH:MM 格式包含 hourminute

  • 'seconds': 以 HH:MM:SS 格式包含 hourminutesecond

  • '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__()

对于一个时间 tstr(t) 等同于 t.isoformat()

time.strftime(format)

返回一个表示时间的字符串,由显式格式字符串控制。另请参阅 strftime() 和 strptime() 的行为time.isoformat()

time.__format__(format)

time.strftime() 相同。这使得在格式化字符串字面值中以及使用 str.format() 时可以为 time 对象指定格式字符串。另请参阅 strftime() 和 strptime() 的行为time.isoformat()

time.utcoffset()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.utcoffset(None),如果后者不返回 None 或一个大小小于一天的 timedelta 对象,则引发异常。

在 3.7 版更改: UTC 偏移量不再限制为整数分钟。

time.dst()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(None),如果后者不返回 None 或一个大小小于一天的 timedelta 对象,则引发异常。

在 3.7 版更改: DST 偏移量不再限制为整数分钟。

time.tzname()

如果 tzinfoNone,则返回 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(的一个具体子类)的实例可以传递给 datetimetime 对象的构造函数。后者对象将其属性视为本地时间,而 tzinfo 对象支持的方法可以揭示本地时间与 UTC 的偏移量、时区名称和夏令时偏移量,所有这些都相对于传递给它们的日期或时间对象。

你需要派生一个具体的子类,并且(至少)提供你所使用的 datetime 方法所需的标准 tzinfo 方法的实现。datetime 模块提供了 timezone,这是一个 tzinfo 的简单具体子类,可以表示与 UTC 有固定偏移量的时区,例如 UTC 本身或北美的 EST 和 EDT。

对 pickling 的特殊要求:tzinfo 子类必须有一个可以无参数调用的 __init__() 方法,否则它可以被 pickle,但可能无法再次 unpickle。这是一个技术要求,将来可能会放宽。

tzinfo 的具体子类可能需要实现以下方法。具体需要哪些方法取决于对感知 datetime 对象的使用。如果不确定,只需实现所有方法。

tzinfo.utcoffset(dt)

返回本地时间与 UTC 的偏移量,作为一个 timedelta 对象,UTC 以东为正。如果本地时间在 UTC 以西,这应该是负数。

这表示与 UTC 的*总*偏移量;例如,如果一个 tzinfo 对象同时表示时区和夏令时调整,utcoffset() 应该返回它们的总和。如果 UTC 偏移量未知,则返回 None。否则,返回的值必须是一个严格介于 -timedelta(hours=24)timedelta(hours=24) 之间的 timedelta 对象(偏移量的大小必须小于一天)。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 对象,如果 DST 信息未知,则返回 None

如果夏令时未生效,则返回 timedelta(0)。如果夏令时生效,则返回偏移量作为一个 timedelta 对象(详见 utcoffset())。请注意,夏令时偏移量(如果适用)已经加到了 utcoffset() 返回的 UTC 偏移量中,因此除非您有兴趣单独获取夏令时信息,否则无需查阅 dst()。例如,datetime.timetuple() 会调用其 tzinfo 属性的 dst() 方法来确定 tm_isdst 标志应该如何设置,而 tzinfo.fromutc() 会调用 dst() 来考虑跨时区时的夏令时变化。

一个同时模拟标准时间和夏令时的 tzinfo 子类的实例 tz 在此意义上必须保持一致:

tz.utcoffset(dt) - tz.dst(dt)

对于每个 dt.tzinfo == tzdatetime 对象 dt,必须返回相同的结果。对于正常的 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.

    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""US/Eastern""America/New York" 都是有效的回复。如果字符串名称未知,则返回 None。请注意,这是一个方法而不是一个固定的字符串,主要是因为一些 tzinfo 子类希望根据传递的 dt 的具体值返回不同的名称,特别是如果 tzinfo 类考虑了夏令时。

tzname() 的默认实现会引发 NotImplementedError

这些方法由 datetimetime 对象调用,以响应它们同名的方法。一个 datetime 对象将自身作为参数传递,而一个 time 对象将 None 作为参数传递。因此,tzinfo 子类的方法应该准备好接受一个为 Nonedatetime 类的 dt 参数。

当传递 None 时,由类的设计者决定最佳响应。例如,如果类希望表示时间对象不参与 tzinfo 协议,则返回 None 是合适的。让 utcoffset(None) 返回标准 UTC 偏移量可能更有用,因为没有其他约定来发现标准偏移量。

当一个 datetime 对象作为对 datetime 方法的响应被传入时,dt.tzinfoself 是同一个对象。tzinfo 方法可以依赖于此,除非用户代码直接调用 tzinfo 方法。其意图是让 tzinfo 方法将 dt 解释为本地时间,而无需担心其他时区的对象。

还有一个 tzinfo 方法,子类可能希望覆盖:

tzinfo.fromutc(dt)

这从默认的 datetime.astimezone() 实现中调用。当从那里调用时,dt.tzinfoself,并且 dt 的日期和时间数据被视为表示 UTC 时间。fromutc() 的目的是调整日期和时间数据,返回一个等效的在 self 的本地时间中的日期时间。

大多数 tzinfo 子类应该能够毫无问题地继承默认的 fromutc() 实现。它足够强大,可以处理固定偏移时区,以及同时考虑标准时间和夏令时的时区,并且后者即使在不同年份的夏令时转换时间不同时也能处理。默认 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
# https://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 子类中,每年有两次在夏令时转换点存在不可避免的微妙之处。为具体起见,考虑美国东部时间(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

当夏令时开始时(“start”行),本地挂钟时间从 1:59 跳到 3:00。在那一天,形式为 2:MM 的挂钟时间实际上没有意义,因此在夏令时开始的那天,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

当夏令时结束时(“end”行),有一个可能更糟的问题:有一个小时在本地挂钟时间中无法明确表示:夏令时的最后一个小时。在东部时区,这是夏令时结束当天 UTC 时间 5:MM 形式的时间。本地挂钟时间从 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

请注意,仅在 fold 属性的值上有所不同的 datetime 实例在比较中被认为是相等的。

无法承受挂钟时间歧义的应用程序应明确检查 fold 属性的值,或避免使用混合 tzinfo 子类;在使用 timezone 或任何其他固定偏移 tzinfo 子类(例如仅代表 EST(固定偏移 -5 小时)或仅代表 EDT(固定偏移 -4 小时)的类)时,没有歧义。

参见

zoneinfo

datetime 模块有一个基本的 timezone 类(用于处理与 UTC 的任意固定偏移)及其 timezone.utc 属性(一个 UTC timezone 实例)。

zoneinfo 将 *IANA 时区数据库*(也称为奥尔森数据库)引入 Python,并推荐使用它。

IANA 时区数据库

时区数据库(通常称为 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() 方法返回的值。

在 3.2 版本加入。

在 3.7 版更改: UTC 偏移量不再限制为整数分钟。

timezone.utcoffset(dt)

返回在构造 timezone 实例时指定的固定值。

dt 参数被忽略。返回值是一个 timedelta 实例,等于本地时间与 UTC 之间的差异。

在 3.7 版更改: UTC 偏移量不再限制为整数分钟。

timezone.tzname(dt)

返回在构造 timezone 实例时指定的固定值。

如果在构造函数中未提供 nametzname(dt) 返回的名称是根据 offset 的值生成的,如下所示。如果 offsettimedelta(0),则名称为“UTC”,否则它是一个格式为 UTC±HH:MM 的字符串,其中 ± 是 offset 的符号,HH 和 MM 分别是 offset.hoursoffset.minutes 的两位数字。

在 3.6 版更改: offset=timedelta(0) 生成的名称现在是纯粹的 'UTC',而不是 'UTC+00:00'

timezone.dst(dt)

总是返回 None

timezone.fromutc(dt)

返回 dt + offsetdt 参数必须是一个感知的 datetime 实例,其 tzinfo 设置为 self

类属性:

timezone.utc

UTC 时区,timezone(timedelta(0))

strftime()strptime() 的行为

datedatetimetime 对象都支持一个 strftime(format) 方法,用于在显式格式字符串的控制下创建一个表示时间的字符串。

相反,date.strptime()datetime.strptime()time.strptime() 类方法从一个表示时间的字符串和相应的格式字符串创建一个对象。

下表提供了 strftime()strptime() 的高级比较。

strftime

strptime

用法

根据给定格式将对象转换为字符串

根据相应格式将字符串解析为对象

方法类型

实例方法

类方法

签名

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

UTC 偏移量,格式为 ±HH:MM[:SS[.ffffff]](如果对象是简单的,则为空字符串)。

(空), +00:00, -04:00, +10:30, +06:34:15, -03:07:12.345216

(6)

当与 strftime() 方法一起使用时,这些指令可能并非在所有平台上都可用。ISO 8601 年份和 ISO 8601 周指令不能与上面的年份和周数指令互换。使用不完整或模糊的 ISO 8601 指令调用 strptime() 将引发 ValueError

支持的完整格式代码集因平台而异,因为 Python 调用平台 C 库的 strftime() 函数,而平台差异很常见。要查看您平台上支持的完整格式代码集,请查阅 strftime(3) 文档。在处理不支持的格式说明符方面,平台之间也存在差异。

在 3.6 版新增: 增加了 %G, %u%V

在 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 或返回一个空字符串。

备注

  1. 因为格式取决于当前的区域设置,所以在对输出值做假设时应小心。字段顺序会变化(例如,“月/日/年”与“日/月/年”),并且输出可能包含非 ASCII 字符。

  2. strptime() 方法可以解析 [1, 9999] 范围内的年份,但小于 1000 的年份必须用零填充到 4 位宽度。

    在 3.2 版更改: 在以前的版本中,strftime() 方法仅限于年份 >= 1900。

    在 3.3 版更改: 在 3.2 版中,strftime() 方法仅限于年份 >= 1000。

  3. 当与 strptime() 方法一起使用时,%p 指令仅在 %I 指令用于解析小时时才影响输出的小时字段。

  4. time 模块不同,datetime 模块不支持闰秒。

  5. 当与 strptime() 方法一起使用时,%f 指令接受一到六位数字,并在右侧补零。%f 是对 C 标准中格式字符集的扩展(但在 datetime 对象中单独实现,因此始终可用)。

  6. 对于简单对象,%z%:z%Z 格式代码被替换为空字符串。

    对于感知对象:

    %z

    utcoffset() 被转换为 ±HHMM[SS[.ffffff]] 形式的字符串,其中 HH 是一个两位数的字符串,表示 UTC 偏移的小时数,MM 是一个两位数的字符串,表示 UTC 偏移的分钟数,SS 是一个两位数的字符串,表示 UTC 偏移的秒数,ffffff 是一个六位数的字符串,表示 UTC 偏移的微秒数。当偏移量是整数秒时,省略 ffffff 部分,当偏移量是整数分钟时,同时省略 ffffffSS 部分。例如,如果 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 的某些值:

    1. 您机器区域设置的 time.tzname 中的任何值

    2. 硬编码值 UTCGMT

    因此,生活在日本的人可能会有 JSTUTCGMT 作为有效值,但可能没有 EST。对于无效值,它将引发 ValueError

    在 3.2 版更改: 当向 strptime() 方法提供 %z 指令时,将生成一个感知的 datetime 对象。结果的 tzinfo 将设置为一个 timezone 实例。

  7. 当与 strptime() 方法一起使用时,%U%W 仅在指定了星期和公历年份 (%Y) 时才用于计算。

  8. %U%W 类似,%V 仅在 strptime() 格式字符串中指定了星期和 ISO 年份 (%G) 时才用于计算。另请注意,%G%Y 不可互换。

  9. 当与 strptime() 方法一起使用时,对于 %d%m%H%I%M%S%j%U%W%V 格式,前导零是可选的。格式 %y 则需要前导零。

  10. 使用 strptime() 解析月份和日期时,请务必在格式中包含年份。如果您需要解析的值缺少年份,请附加一个明确的虚拟闰年。否则,当遇到闰日时,您的代码将引发异常,因为解析器使用的默认年份不是闰年。用户每四年就会遇到这个错误……

    >>> month_day = "02/29"
    >>> datetime.strptime(f"{month_day};1984", "%m/%d;%Y")  # No leap year bug.
    datetime.datetime(1984, 2, 29, 0, 0)
    

    自 3.13 版本起弃用,将在 3.15 版本中移除: 使用包含月中某天但没有年份的格式字符串调用 strptime() 现在会发出 DeprecationWarning。在 3.15 或更高版本中,我们可能会将其更改为错误,或将默认年份更改为闰年。请参阅 gh-70647

脚注