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

源代码: Lib/datetime.py [https://github.com/python/cpython/tree/3.13/Lib/datetime.py]


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

在支持日期时间数学运算的同时,实现的关注点更着重于如何能够更有效地解析其属性用于格式化输出和数据操作。

小技巧

跳到 格式代码

参见

感知型对象和简单型对象

日期和时间对象可以根据它们是否包含时区信息而分为“感知型”和“简单型”两类。

充分掌握应用性算法和政治性时间调整信息例如时区和夏令时的情况下,一个 感知型 对象就能相对于其他感知型对象来精确定位自身时间点。 感知型对象是用来表示一个没有解释空间的固定时间点。 [1]

简单型 对象没有包含足够多的信息来无歧义地相对于其他 date/time 对象来定位自身时间点。 不论一个简单型对象所代表的是世界标准时间(UTC)、当地时间还是某个其他时区的时间完全取决于具体程序,就像一个特定数字所代表的是米、英里还是质量完全取决于具体程序一样。 简单型对象更易于理解和使用,代价则是忽略了某些现实性考量。

对于要求感知型对象的应用,datetimetime 对象具有一个可选的时区信息属性 tzinfo,它可被设为抽象类 tzinfo 的子类的一个实例。 这些 tzinfo 对象会捕获与 UTC 时间的差值、时区名称以及夏令时是否生效等信息。

datetime 模块只提供了一个具体的 tzinfo 类,即 timezone 类。 timezone 类可以表示具有相对于 UTC 的固定时差的简单时区,例如 UTC 本身或北美 EST 和 EDT 时区等。 支持时区的详细程度取决于具体的应用。 世界各地的时间调整规则往往是政治性多于合理性,经常会发生变化,除了 UTC 之外并没有一个能适合所有应用的标准。

常量

datetime 模块导出了以下常量:

Added in version 3.11.

有效的类型

  • class datetime.date
  • 一个理想化的简单型日期,它假设当今的公历在过去和未来永远有效。 属性: year, month, and day
  • class datetime.time
  • 一个独立于任何特定日期的理想化时间,它假设每一天都恰好等于 246060 秒。 (这里没有“闰秒”的概念。) 包含属性: hour, minute, second, microsecondtzinfo
  • class datetime.timedelta
  • 将两个 datetimedate 实例之间的差值表示为微秒级精度的持续时间。
  • class datetime.tzinfo
  • 一个描述时区信息对象的抽象基类。 用来给 datetimetime 类提供自定义的时间调整概念(例如处理时区和/或夏令时)。
  • class datetime.timezone
  • 一个实现了 tzinfo 抽象基类的子类,用于表示相对于 世界标准时间(UTC)的偏移量。

Added in version 3.2.

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

子类关系

  1. object
  2. timedelta
  3. tzinfo
  4. timezone
  5. time
  6. date
  7. datetime

通用的特征属性

date, datetime, timetimezone 类型共享这些通用特性:

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

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

  • 这些类型的对象支持通过 pickle 模块进行高效的封存。

确定一个对象是感知型还是简单型

date 类型的对象都是简单型的。

timedatetime 类型的对象可以是感知型或者简单型。

一个 datetime 对象 d 在以下条件同时成立时将是感知型的:

  • d.tzinfo 不为 None

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

在其他情况下,d 将是简单型的。

一个 time 对象 t 在以下条件同时成立时将是感知型的:

  • t.tzinfo 不为 None

  • 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。 这些参数可以是整数或者浮点数,并可以为正值或者负值。

只有 days, seconds 和 microseconds 会存储在内部。 参数单位的换算规则如下:

  • 1毫秒会转换成1000微秒。

  • 1分钟会转换成60秒。

  • 1小时会转换成3600秒。

  • 1星期会转换成7天。

日期、秒、微秒都是标准化的,所以它们的表达方式也是唯一的,例:

  • 0 <= microseconds < 1000000

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

  • -999999999 <= days <= 999999999

下面的例子演示了如何对 days, seconds 和 microseconds 以外的任意参数执行“合并”操作并标准化为以上三个结果属性:

  1. >>> from datetime import timedelta
  2. >>> delta = timedelta(
  3. ... days=50,
  4. ... seconds=27,
  5. ... microseconds=10,
  6. ... milliseconds=29000,
  7. ... minutes=5,
  8. ... hours=8,
  9. ... weeks=2
  10. ... )
  11. >>> # 只保留日期、秒和微秒
  12. >>> delta
  13. datetime.timedelta(days=64, seconds=29156, microseconds=10)

在有任何参数为浮点型并且 microseconds 值为小数的情况下,从所有参数中余下的微秒数将被合并,并使用四舍五入偶不入奇的规则将总计值舍入到最接近的整数微秒值。 如果没有任何参数为浮点型的情况下,则转换和标准化过程将是完全精确的(不会丢失信息)。

如果标准化后的 days 数值超过了指定范围,将会抛出 OverflowError 异常。

请注意对负数值进行标准化的结果可能会令人感到惊讶。 例如:

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

类属性:

  • timedelta.min
  • The most negative timedelta object, timedelta(-999999999).
  • timedelta.max
  • The most positive timedelta object, 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() 值时无意中使用了这个属性:

  1. >>> from datetime import timedelta
  2. >>> duration = timedelta(seconds=11235813)
  3. >>> duration.days, duration.seconds
  4. (130, 3813)
  5. >>> duration.total_seconds()
  6. 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 or t1 = i * t2 时差乘以一个整数。 运算后如果 i != 0t1 // i == t2 为真值。
通常情况下,t1 * i == t1 * (i-1) + t1 为真值。 (1)
t1 = t2 * f or t1 = f * t2 乘以一个浮点数,结果会被舍入到 timedelta 最接近的整数倍。 精度使用四舍五偶入奇不入规则。
f = t2 / t3 总时长 t2 除以间隔单位 t3 (3)。 返回一个 float 对象。
t1 = t2 / f or t1 = t2 / i 除以一个浮点数或整数。 结果会被舍入到 timedelta 最接近的整数倍。 精度使用四舍五偶入奇不入规则。
t1 = t2 // i or t1 = t2 // t3 计算底数,其余部分(如果有)将被丢弃。在第二种情况下,将返回整数。 (3)
t1 = t2 % t3 余数为一个 timedelta 对象。(3)
q, r = divmod(t1, t2) 计算商和余数: q = t1 // t2 (3) 和 r = t1 % t2q 是一个整数而 r 是一个 timedelta 对象。
+t1 返回一个相同数值的 timedelta 对象。
-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 对象的字符串表示形式,作为附带正规属性值的构造器调用。

注释:

  • 结果正确,但可能会溢出。

  • 结果正确,不会溢出。

  • 除以零将会引发 ZeroDivisionError

  • -timedelta.max 不可以表示为一个 timedelta 对象。

  • timedelta 对象的字符串表示形式类似于其内部表示形式被规范化。对于负时间增量,这会导致一些不寻常的结果。例如:

  1. >>> timedelta(hours=-5)
  2. datetime.timedelta(days=-1, seconds=68400)
  3. >>> print(_)
  4. -1 day, 19:00:00
  • 表达式 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年视为一个较大的时间间隔)。

Added in version 3.2.

timedelta 用法示例

一个标准化的附加示例:

  1. >>> # another_year 的部分增加恰好 365 天
  2. >>> from datetime import timedelta
  3. >>> year = timedelta(days=365)
  4. >>> another_year = timedelta(weeks=40, days=84, hours=23,
  5. ... minutes=50, seconds=600)
  6. >>> year == another_year
  7. True
  8. >>> year.total_seconds()
  9. 31536000.0

timedelta 算术运算的示例:

  1. >>> from datetime import timedelta
  2. >>> year = timedelta(days=365)
  3. >>> ten_years = 10 * year
  4. >>> ten_years
  5. datetime.timedelta(days=3650)
  6. >>> ten_years.days // 365
  7. 10
  8. >>> nine_years = ten_years - year
  9. >>> nine_years
  10. datetime.timedelta(days=3285)
  11. >>> three_years = nine_years // 3
  12. >>> three_years, three_years.days // 365
  13. (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 <= 日期 <= 给定年月对应的天数

如果参数不在这些范围内,则抛出 ValueError 异常。

其它构造器,所有的类方法:

  • classmethod date.today()
  • 返回当前的本地日期。

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

  • classmethod date.fromtimestamp(timestamp)
  • 返回对应于 POSIX 时间戳的当地时间,例如 time.time() 返回的就是时间戳。

这可能引发 OverflowError,如果时间戳数值超出所在平台 C localtime() 函数的支持范围的话,并且会在 localtime() 出错时引发 OSError。 通常该数值会被限制在 1970 年至 2038 年之间。 请注意在时间戳概念包含闰秒的非 POSIX 系统上,闰秒会被 fromtimestamp() 所忽略。

在 3.3 版本发生变更: 引发 OverflowError 而不是 ValueError,如果时间戳数值超出所在平台 C localtime() 函数的支持范围的话,并会在 localtime() 出错时引发 OSError 而不是 ValueError

  • classmethod date.fromordinal(ordinal)
  • 返回对应于预期格列高利历序号的日期,其中公元 1 年 1 月 1 日的序号为 1。

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

  • classmethod date.fromisoformat(date_string)
  • 返回一个对应于以任何有效 ISO 8601 格式给出的 date_string 的 date,下列格式除外:
  • 目前不支持降低精度的日期 (YYYY-MM, YYYY)。

  • 目前不支持扩展日期表示形式 (±YYYYYY-MM-DD)。

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

示例:

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

Added in version 3.7.

在 3.11 版本发生变更: 在之前版本中,此方法仅支持一种格式 YYYY-MM-DD

  • classmethod date.fromisocalendar(year, week, day)
  • 返回指定 year, week 和 day 所对应 ISO 历法日期的 date。 这是函数 date.isocalendar() 的逆操作。

Added in version 3.8.

类属性:

  • date.min
  • 最小的日期 date(MINYEAR, 1, 1)
  • date.max
  • 最大的日期 ,date(MAXYEAR, 12, 31)
  • date.resolution
  • 两个日期对象的最小间隔,timedelta(days=1)

实例属性(只读):

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

注释:

  • 如果 timedelta.days > 0 则 date2 将在时间线上前进,如果 timedelta.days < 0 则将后退。 操作完成后 date2 - date1 == timedelta.daystimedelta.secondstimedelta.microseconds 会被忽略。 如果 date2.year 将小于 MINYEAR 或大于 MAXYEAR 则会引发 OverflowError

  • timedelta.secondstimedelta.microseconds 会被忽略。

  • 该值是精确的,且不会溢出。 运算后 timedelta.secondstimedelta.microseconds 均为 0,且 date2 + timedelta == date1

  • date 对象在表示相同的日期时相等。

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

  • 当 date1 的时间在 date2 之前则认为 date1 小于 date2。 换句话说,当且仅当 date1.toordinal() < date2.toordinal()date1 < date2

不同时为 datetime 实例的 date 实例和 datetime 对象之间的顺序比较将会引发 TypeError

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

在布尔运算中,所有 date 对象都会被视为真值。

实例方法:

  • date.replace(year=self.year, month=self.month, day=self.day)
  • 返回一个具有同样值的日期,除非通过任何关键字参数给出了某些形参的新值。

示例:

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

date 对象也被泛型函数 copy.replace() 所支持。

hours, minutes 和 seconds 值均为 0,且 DST 旗标值为 -1。

d.timetuple() 等价于:

  1. 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 对象 d,均有 date.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()
  • 返回一个由三部分组成的 named tuple 对象: year, weekweekday

ISO 历法是一种被广泛使用的格列高利历。 [3]

ISO 年由 52 或 53 个完整星期构成,每个星期开始于星期一结束于星期日。 一个 ISO 年的第一个星期就是(格列高利)历法的一年中第一个包含星期四的星期。 这被称为 1 号星期,这个星期四所在的 ISO 年与其所在的格列高利年相同。

例如,2004 年的第一天是星期四,因此 ISO 2004 年的第一个星期开始于 2003 年 12 月 29 日星期一,结束于 2004 年 1 月 4 日星期日:

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

在 3.9 版本发生变更: 结果由元组改为 named tuple

  • date.isoformat()
  • 返回一个以 ISO 8601 格式 YYYY-MM-DD 来表示日期的字符串:
  1. >>> from datetime import date
  2. >>> date(2002, 12, 4).isoformat()
  3. '2002-12-04'
  • date.str()
  • 对于日期 dstr(d) 等价于 d.isoformat()
  • date.ctime()
  • 返回一个表示日期的字符串:
  1. >>> from datetime import date
  2. >>> date(2002, 12, 4).ctime()
  3. 'Wed Dec 4 00:00:00 2002'

d.ctime() 等效于:

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

在原生 C ctime() 函数遵循 C 标准的平台上 (time.ctime() 会发起对该函数的调用,但 date.ctime() 并不会) 。