添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Python 中内置了许多和操作时间有关的 API,它们分布在 time datetime 等标准库中,用法繁多且容易混淆,本文将力求清晰地阐述这些 API 的关键部分和区别,帮助你了解并掌握其用法。

下文将分别介绍每个模块的主要目的、核心对象、常用方法以及用途,并在最后做分析对比,如果已经了解这些细节可以直接跳转到结尾的总结对比部分。

另外本文将避免涉及字符串格式化、时区、冬夏令时等更复杂深入的话题。

time 模块

概括来说, time 模块通过系统底层的计时器获取自 epoch 以来经过的总秒数(可能为浮点数),即我们常说的 POSIX 时间戳(timestamp)。它的用法较为低阶,适合用做精确计时。对 Unix 系统来说, epoch 1970年1月1日 00:00:00(UTC) ,因此该模块也可以将时间戳转换为具体的日期时间,但表示日期时间的对象结构非常简单,不适合进行复杂的操作和表示。

time 模块的 API 中只有一个类: time.struct_time

struct_time 是一个转换 epoch 以来经过秒数得到的结构化的时间对象,它提供了类似 namedtuple 的 API,可以通过下标或属性名称获取对象的年月日时分秒等属性。调用 gmtime() localtime() strptime() 等方法可得到 struct_time 实例。

>>> st = time.localtime()
time.struct_time(tm_year=2021, tm_mon=4, tm_mday=29, tm_hour=12, tm_min=39, tm_sec=14, tm_wday=3, tm_yday=119, tm_isdst=0)
>>> st.tm_mon
>>> st[1]

从示例中可以看到,struct_time 实例实质是一个数字组成的类元祖序列,该模块中接收 struct_time 实例作为参数的函数都可以直接接收一个同样长度的元祖。它只能简单的记录通过换算时间戳得到的年月日时分等属性,没有提供支持额外操作的其他方法,因此实践中的用途非常有限。

>>> st1 = time.localtime()
>>> st2 = time.localtime()
>>> st2 - st1
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    st2 - st1
TypeError: unsupported operand type(s) for -: 'time.struct_time' and 'time.struct_time'

常见用途与函数

time.time() 以浮点数的形式返回自 epoch 以来经过的时间秒数。常见用法是通过计算两次调用之间的间隔来得出程序执行时间。

>>> time.time()
1619665423.683973
>>> now = time.time()
>>> time.gmtime(now)
time.struct_time(tm_year=2021, tm_mon=4, tm_mday=29, tm_hour=4, tm_min=51, tm_sec=54, tm_wday=3, tm_yday=119, tm_isdst=0)
>>> time.gmtime()
time.struct_time(tm_year=2021, tm_mon=4, tm_mday=29, tm_hour=4, tm_min=51, tm_sec=56, tm_wday=3, tm_yday=119, tm_isdst=0)

time.strftime(format[, t]) 将一个 struct_time 对象按指定的 format 编码格式化为字符串,t 的默认值是 time.localtime() 的返回值。

>>> time.strftime('%H:%M:%S')
'13:10:37'

time.strptime(string[, format]) 将一个字符串按指定的 format 编码解析为 struct_time 对象,format 的默认值为 "%a %b %d %H:%M:%S %Y"

>>> time.strptime("30 Nov 00", "%d %b %y")   
time.struct_time(tm_year=2000, tm_mon=11, tm_mday=30, tm_hour=0, tm_min=0,
                 tm_sec=0, tm_wday=3, tm_yday=335, tm_isdst=-1)

如上示例,解析时未提供的时间单位将使用默认值填充。

datetime 模块

datetime 模块支持日期和时间的运算,但实现的重点是为输出格式化和操作提供高效的属性提取。

datetime 模块提供了一些用于操作日期和时间的类。该模块的绝大部分功能都围绕着以下 4 个类(以及另外两个关于时区的类)的方法和属性来实现。一个容易让人混淆的点是,虽然它们全都是 Python 类,但在命名中并未遵循首字母大写的惯例,在导入时看上去就像是 datetime 下的子包或者子模块。

我们将简要介绍每一个类常用的实例构造方式、支持的操作符、实例方法以及实例属性。

表示日期类型。

实例构造方式

实例化 date 类,需要传入日期对应的年月日参数。

>>> date(2021, 4, 29)
datetime.date(2021, 4, 29)
  • 支持与另一 date 对象进行 ==<> 等比较操作。
  • 支持与 timedelta 对象进行加减操作,结果依然为 date 对象。
  • 支持与另一 date 对象进行相减操作,得到 timedelta 对象。
  • 支持哈希。
  • strftime(self, fmt) 按指定的 fmt 格式化编码返回当前 date 对象的字符串表示。

    >>> d1 = date.today()
    >>> d1.strftime('%Y-%m-%d')
    '2021-04-29'
    
  • 支持哈希。
  • time 对象不支持与 timetimedelta 进行加减操作,如果我们想计算两个 time 对象之间的时间间隔,可以使用 datetime.combine() 将它们处理为日期相同的 datetime 对象再进行计算:

    >>> datetime.combine(date.today(), t2) - datetime.combine(date.today(), t1) 
    datetime.timedelta(seconds=4440)
    

    strftime(self, fmt) 按指定的 fmt 格式化编码返回当前 time 对象的字符串表示。

    >>> t = time.fromisoformat('17:32:10')
    >>> t.strftime('%Hh %Mm %Ss')
    '17h 32m 10s'
    

    replace(self,hour=None,minute=None,second=None,microsecond=None, tzinfo=True, *,fold=None) 返回替换当前 time 对象的某一属性后的副本。

    >>> t.replace(hour=20)
    datetime.time(20, 27, 55)
    

    datetime

    表示包含日期时分的时间类型,是 date 的子类,因此也继承了 date 的所有属性和方法。它的实例还可以视作 datetime 实例的组合体,因此同时具备了两种对象的大部分方法和属性。

    下文的介绍中不包含从 date 继承的方法和属性。

    实例构造方式

    实例化 datetime 类并传入对应参数,接收参数为 datetime 实例化参数的组合,其中日期参数为必填参数,其他参数有默认值。

    >>> datetime(year=2021, month=4, day=29)
    datetime.datetime(2021, 4, 29, 0, 0)
    
    >>> datetime.now()
    datetime.datetime(2021, 4, 29, 16, 4, 53, 648203)
    >>> datetime.utcnow()
    datetime.datetime(2021, 4, 29, 8, 5, 1, 671572)
    

    调用 datetime.fromtimestamp(timestamp)datetime.utcfromtimestamp(timestamp) 类方法并传入时间戳,区别为实例的对应时区不同。

    >>> import time
    >>> datetime.utcfromtimestamp(time.time())
    datetime.datetime(2021, 4, 29, 8, 6, 4, 798136)
    >>> datetime.fromtimestamp(time.time())
    datetime.datetime(2021, 4, 29, 16, 6, 26, 251251)
    

    支持的操作符

  • datetime 支持与 date 进行相等比较,但结果一定为 False ,除此之外只支持与另一 datetime 对象执行 ==<> 等比较操作。
  • 支持与 timedelta 相加,结果为 datetime;支持与 timedelta 对象进行加减,结果依然为 datetime 对象,与另一 datetime 对象进行相减,得到 timedelta 对象。
  • 同样支持哈希。
  • 除了从 date 继承的 strftime()timetuple()isoformat()replace()等方法外,还拥有以下方法:

    timestamp(self) 返回一个浮点数格式的 POSIX 时间戳。

    >>> dt = datetime.now()
    >>> dt.timestamp()
    1619685580.762657
    >>> td = dt1 - dt2
    datetime.timedelta(days=-1, seconds=86395, microseconds=573188)
    >>> td.total_seconds()
    -4.426812
    >>> abs(td)
    datetime.timedelta(seconds=4, microseconds=426812)
    
    >>> d1 = timedelta(minutes=3, seconds=35)
    datetime.timedelta(days=0, seconds=215, microseconds=0)
    >>> d2 = timedelta(days=1)
    datetime.timedelta(days=1)
    >>> d2.seconds
    

    timedatetime 模块的区别:

  • time 模块,获取系统时间戳,主要用于计时或表示某一时间点,可以通过数值元祖表示结构化的日期时间,但不支持进一步的转换或操作。
  • datetime 模块,基于时间戳构建高阶的日期、时间、间隔等对象,支持丰富的转换方式和操作。
  • datetime 模块中不同对象的区别:

  • date 只表示日期。支持与 datetimedelta 进行加减操作.
  • time 只表示时分。不支持与 timetimedelta 进行加减操作,计算间隔需要先转换成 datetime 对象。
  • datetime 同时表示日期和时分的时间对象。同时具备 datetime 对象的行为和属性,可以从中解析出单独的 datetime 对象。
  • timedelta 表示两个时间之间的间隔。只通过 dayssecondsmicroseconds 这 3 种单位来表示。
  • 字符串格式化与解析

    字符串格式化与解析:

    time.struct_timedatetime.datedatetime.timedatetime.datetime 等对象都可以通过 strftime() (string format)实例方法或函数转换为指定格式的字符串。

    特定格式的字符串仅可以通过 strptime()(string parse)类方法或函数直接转换为time.struct_timedatetime.datetime 对象。

    ISO 格式字符串格式化与解析:

    datetime.datedatetime.timedatetime.datetime 等对象都可以通过 isoformat() 实例方法转换为 ISO 8601 格式的字符串。

    ISO 8601 格式的字符串可以通过 fromisoformat() 类方法直接转换为datetime.datedatetime.timedatetime.datetime 对象。

    用一张时序图总结上文内容:

  • [ts] 表示该参数具有默认值是可选的。
  • 请注意区分图中的实例方法、类方法以及模块函数:
  • 名称中以 time. 开头的均为 time 模块的函数
  • 名称中以 obj. 开头的均为 datetimedatetime 对象的实例方法
  • 其余名称的函数均为类方法
  •