8.1. datetime — 基本日期和时间类型 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/datetime
跳转至:导航、​搜索

8.1. 约会时间 — 基本日期和时间类型

源代码: :source:`Lib/datetime.py`



datetime 模块提供了以简单和复杂方式操作日期和时间的类。 虽然支持日期和时间算术,但实现的重点是高效的属性提取以进行输出格式化和操作。 有关相关功能,另请参阅 timecalendar 模块。

有两种日期和时间对象:“naive”和“aware”。

感知对象具有足够的适用算法和政治时间调整知识,例如时区和夏令时信息,以相对于其他感知对象定位自身。 一个有意识的对象被用来表示一个特定的时刻,它是不可解释的 1

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

对于需要感知对象的应用程序,datetimetime 对象有一个可选的时区信息属性,tzinfo,可以设置为抽象子类的实例tzinfo 类。 这些 tzinfo 对象捕获有关 UTC 时间偏移量、时区名称以及夏令时是否生效的信息。 请注意,datetime 模块仅提供一个具体的 tzinfo 类,即 timezone 类。 timezone 类可以表示与 UTC 有固定偏移的简单时区,例如 UTC 本身或北美 EST 和 EDT 时区。 在更深层次的细节支持时区取决于应用程序。 世界各地的时间调整规则政治性多于理性,变化频繁,除UTC之外没有适用于所有应用的标准。

datetime 模块导出以下常量:

datetime.MINYEAR
datedatetime 对象中允许的最小年份数。 MINYEAR1
datetime.MAXYEAR
datedatetime 对象中允许的最大年份数。 MAXYEAR9999

也可以看看

模块 日历
通用日历相关功能。
模块时间
时间访问和转换。


8.1.1. 可用类型

class datetime.date
一个理想化的天真日期,假设当前的公历一直有效,并且永远有效。 属性:
class datetime.time
一个理想化的时间,独立于任何特定的一天,假设每天正好有 24*60*60 秒(这里没有“闰秒”的概念)。 属性:小时分钟微秒tzinfo
class datetime.datetime
日期和时间的组合。 属性:小时分钟微秒tzinfo
class datetime.timedelta
将两个 datetimedatetime 实例之间的差异表示为微秒分辨率的持续时间。
class datetime.tzinfo
时区信息对象的抽象基类。 datetimetime 类使用这些来提供可定制的时间调整概念(例如,考虑时区和/或夏令时)。
class datetime.timezone

tzinfo 抽象基类实现为与 UTC 的固定偏移量的类。

3.2 版中的新功能。

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

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

timedatetime 类型的对象可能是幼稚的或有意识的。 datetime 对象 d 知道 d.tzinfo 不是 None 并且 d.tzinfo.utcoffset(d) 不返回 None。 如果 d.tzinfoNone,或者如果 d.tzinfo 不是 Noned.tzinfo.utcoffset(d) 返回 Noned 天真。 time 对象 t 知道 t.tzinfo 不是 None 并且 t.tzinfo.utcoffset(None) 不返回 None。 否则, t 是幼稚的。

naive 和aware 之间的区别不适用于 timedelta 对象。

子类关系:

object
    timedelta
    tzinfo
        timezone
    time
    date
        datetime

8.1.2. 时间增量对象

timedelta 对象表示持续时间,即两个日期或时间之间的差异。

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

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

只有微秒在内部存储。 参数被转换为这些单位:

  • 一毫秒转换为 1000 微秒。

  • 一分钟转换为 60 秒。

  • 一小时转换为 3600 秒。

  • 一周转换为 7 天。

然后将天、秒和微秒归一化,以便表示是唯一的,其中

  • 0 <= microseconds < 1000000

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

  • -999999999 <= days <= 999999999

如果任何参数是浮点数并且存在小数微秒,则将从所有参数中剩余的小数微秒组合起来,并使用舍入半到偶数决胜局将它们的总和四舍五入到最接近的微秒。 如果没有参数是浮点数,则转换和规范化过程是精确的(没有信息丢失)。

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

请注意,负值的归一化起初可能会令人惊讶。 例如,

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

类属性是:

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 对象。

实例属性(只读):

属性 价值
days -999999999 和 999999999 之间(含)
seconds 0 到 86399 之间(含)
microseconds 0 到 999999 之间(含)

支持的操作:

手术 结果
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 Delta 乘以一个整数。 之后 t1 // i == t2 为真,前提是 i != 0
一般来说,t1 * i == t1 * (i-1) + t1 是真的。 (1)
t1 = t2 * f or t1 = f * t2 Delta 乘以浮点数。 结果使用舍入到偶数舍入到最接近的 timedelta.resolution 倍数。
f = t2 / t3 t2 除以 t3 的除法 (3)。 返回一个 float 对象。
t1 = t2 / f or t1 = t2 / i Delta 除以浮点数或整数。 结果使用舍入到偶数舍入到最接近的 timedelta.resolution 倍数。
t1 = t2 // it1 = t2 // t3 计算地板并丢弃剩余部分(如果有)。 在第二种情况下,返回一个整数。 (3)
t1 = t2 % t3 余数计算为 timedelta 对象。 (3)
q, r = divmod(t1, t2) 计算商和余数:q = t1 // t2 (3) 和 r = t1 % t2。 q 是一个整数,r 是一个 timedelta 对象。
+t1 返回具有相同值的 timedelta 对象。 (2)
-t1 相当于 timedelta(-t1.days, -t1.seconds, -t1.microseconds),和 t1 * -1。 (1)(4)
abs(t) t.days >= 0 时相当于 +tt.days < 0 时相当于 -t。 (2)
str(t) [D day[s], ][H]H:MM:SS[.UUUUUU] 形式返回字符串,其中 D 为负数表示负数 t。 (5)
repr(t) datetime.timedelta(D[, S[, U]]) 形式返回字符串,其中 D 为负数表示负数 t。 (5)

笔记:

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

  2. 这是准确的,不能溢出。

  3. 除以 0 会引发 ZeroDivisionError

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

  5. timedelta 对象的字符串表示与它们的内部表示类似地标准化。 这导致负时间增量的一些不寻常的结果。 例如:

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

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

在 3.2 版中更改: 现在支持 timedelta 对象与另一个 timedelta 对象的底除法和真正除法,以及余数运算和 divmod () 函数。 现在支持 [X38X]timedelta 对象与 float 对象的真正除法和乘法。


支持 timedelta 对象与 timedelta 对象的比较,表示较小的持续时间被认为是较小的 timedelta。 为了阻止混合类型比较返回到按对象地址进行的默认比较,当将 timedelta 对象与不同类型的对象进行比较时,会引发 TypeError,除非比较是 ==!=。 后一种情况分别返回 FalseTrue

timedelta 对象是 hashable(可用作字典键),支持高效酸洗,并且在布尔上下文中,timedelta 对象被认为是真当且仅当它不等于 timedelta(0)

实例方法:

timedelta.total_seconds()

返回持续时间中包含的总秒数。 相当于 td / timedelta(seconds=1)

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

3.2 版中的新功能。

用法示例:

>>> from datetime import timedelta
>>> year = timedelta(days=365)
>>> another_year = timedelta(weeks=40, days=84, hours=23,
...                          minutes=50, seconds=600)  # adds up to 365 days
>>> year.total_seconds()
31536000.0
>>> year == another_year
True
>>> ten_years = 10 * year
>>> ten_years, ten_years.days // 365
(datetime.timedelta(3650), 10)
>>> nine_years = ten_years - year
>>> nine_years, nine_years.days // 365
(datetime.timedelta(3285), 9)
>>> three_years = nine_years // 3;
>>> three_years, three_years.days // 365
(datetime.timedelta(1095), 3)
>>> abs(three_years - ten_years) == 2 * three_years + year
True

8.1.3. 日期对象

date 对象表示理想化日历中的日期(年、月和日),当前的公历在两个方向上无限延伸。 第 1 年的 1 月 1 日称为第 1 天,第 1 年的 1 月 2 日称为第 2 天,依此类推。 这与 Dershowitz 和 Reingold 的著作 Calendrical Calculations 中的“proleptic Gregorian”日历的定义相匹配,它是所有计算的基准日历。 有关在预测公历序数和许多其他日历系统之间转换的算法,请参阅本书。

class datetime.date(year, month, day)

所有参数都是必需的。 参数可以是整数,范围如下:

  • MINYEAR <= year <= MAXYEAR

  • 1 <= month <= 12

  • 1 <= day <= number of days in the given month and year

如果给出这些范围之外的参数,则会引发 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。 对于任何日期 ddate.fromordinal(d.toordinal()) == d

类属性:

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 时,date1 被认为小于 date2。 (4)

笔记:

  1. 如果 timedelta.days > 0,则 date2 在时间上向前移动,如果 timedelta.days < 0,则向后移动。 之后date2 - date1 == timedelta.daystimedelta.secondstimedelta.microseconds 被忽略。 如果 date2.year 小于 MINYEAR 或大于 MAXYEAR,则会引发 OverflowError
  2. timedelta.secondstimedelta.microseconds 被忽略。
  3. 这是准确的,不能溢出。 timedelta.seconds 和 timedelta.microseconds 为 0,并且 date2 + timedelta == date1 之后。
  4. 换句话说,date1 < date2 当且仅当 date1.toordinal() < date2.toordinal()。 如果另一个比较对象不是 date 对象,则日期比较会引发 TypeError。 但是,如果另一个比较对象具有 timetuple() 属性,则会返回 NotImplemented。 这个钩子为其他类型的日期对象提供了实现混合类型比较的机会。 如果不是,当 date 对象与不同类型的对象进行比较时,除非比较是 ==!=,否则会引发 TypeError。 后一种情况分别返回 FalseTrue

日期可以用作字典键。 在布尔上下文中,所有 date 对象都被认为是 true。

实例方法:

date.replace(year=self.year, month=self.month, day=self.day)
返回具有相同值的日期,除了那些由指定的关键字参数赋予新值的参数。 例如,如果 d == date(2002, 12, 31),则 d.replace(day=26) == date(2002, 12, 26)
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()

返回一个 3 元组,(ISO 年份、ISO 周数、ISO 工作日)。

ISO 日历是一种广泛使用的公历变体。 请参阅 https://www.staff.science.uu.nl/~gent0113/calendar/isocalendar.htm 以获得很好的解释。

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

例如,2004 从星期四开始,因此 ISO 2004 年的第一周从 2003 年 12 月 29 日星期一开始,到 2004 年 1 月 4 日星期日结束,因此 date(2003, 12, 29).isocalendar() == (2004, 1, 1)date(2004, 1, 4).isocalendar() == (2004, 1, 7)

date.isoformat()
以 ISO 8601 格式返回一个表示日期的字符串,'YYYY-MM-DD'。 例如,date(2002, 12, 4).isoformat() == '2002-12-04'
date.__str__()
对于日期 dstr(d) 等价于 d.isoformat()
date.ctime()
返回表示日期的字符串,例如 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.__format__(format)
date.strftime() 相同。 这使得可以在 格式化字符串文字 和使用 str.format() 时为 date 对象指定格式字符串。 有关格式化指令的完整列表,请参阅 strftime() 和 strptime() 行为

计算事件天数的示例:

>>> 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)
>>> 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 )
>>> d.isoformat()
'2002-03-11'
>>> d.strftime("%d/%m/%y")
'11/03/02'
>>> d.strftime("%A %d. %B %Y")
'Monday 11. March 2002'
>>> 'The {1} is {0:%d}, the {2} is {0:%B}.'.format(d, "day", "month")
'The day is 11, the month is March.'

8.1.4. 约会时间对象

datetime 对象是包含来自 date 对象和 time 对象的所有信息的单个对象。 与 date 对象一样,datetime 假定当前的公历向两个方向扩展; 就像一个时间对象,datetime 假设每天正好有 3600*24 秒。

构造函数:

class datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)

年、月和日参数是必需的。 tzinfo 可以是 None,或 tzinfo 子类的实例。 其余参数可能是整数,范围如下:

  • MINYEAR <= year <= MAXYEAR,

  • 1 <= month <= 12,

  • 1 <= day <= number of days in the given month and year,

  • 0 <= hour < 24,

  • 0 <= minute < 60,

  • 0 <= second < 60,

  • 0 <= microsecond < 1000000,

  • fold in [0, 1]

如果给出这些范围之外的参数,则会引发 ValueError

3.6 新功能: 添加 fold 参数。

其他构造函数,所有类方法:

classmethod datetime.today()
返回当前本地日期时间,使用 tzinfo None。 这相当于 datetime.fromtimestamp(time.time())。 另见 now()fromtimestamp()
classmethod datetime.now(tz=None)

返回当前本地日期和时间。 如果可选参数 tzNone 或未指定,则类似于 today(),但是,如果可能,提供比通过通过time.time() 时间戳(例如,这可能在提供 C gettimeofday() 函数的平台上是可能的)。

如果 tz 不是 None,则必须是 tzinfo 子类的实例,并将当前日期和时间转换为 tz' s 时区。 在这种情况下,结果等同于 tz.fromutc(datetime.utcnow().replace(tzinfo=tz))。 另见 today()utcnow()

classmethod datetime.utcnow()
返回当前 UTC 日期和时间,使用 tzinfo None。 这类似于 now(),但返回当前 UTC 日期和时间,作为一个简单的 datetime 对象。 可以通过调用 datetime.now(timezone.utc) 获得感知的当前 UTC 日期时间。 另见 now()
classmethod datetime.fromtimestamp(timestamp, tz=None)

返回POSIX时间戳对应的本地日期时间,如time.time()返回。 如果可选参数 tzNone 或未指定,则时间戳将转换为平台的本地日期和时间,并且返回的 datetime 对象是朴素的。

如果tz不是None,则必须是tzinfo子类的实例,时间戳转换为tz的时区. 在这种情况下,结果等同于 tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz))

fromtimestamp() 可能会引发 OverflowError,如果时间戳超出平台 C localtime()gmtime() 函数支持的值范围,以及 localtime()gmtime() 故障上的 OSError。 这通常被限制在 1970 年到 2038 年之间。 请注意,在时间戳概念中包含闰秒的非 POSIX 系统上,fromtimestamp() 会忽略闰秒,然后可能有两个相差一秒的时间戳产生相同的 ]datetime 对象。 另见 utcfromtimestamp()

在 3.3 版更改:如果时间戳超出平台 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)

除了后一个公式始终支持完整的年份范围:介于 MINYEARMAXYEAR 之间。

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

classmethod datetime.fromordinal(ordinal)
返回对应于预测格列高利序数的 datetime,其中第 1 年的 1 月 1 日的序数为 1。 除非 1 <= ordinal <= datetime.max.toordinal(),否则会引发 ValueError。 结果的时分秒微秒均为0,tzinfoNone
classmethod datetime.combine(date, time, tzinfo=self.tzinfo)

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

对于任何 datetime 对象 dd == datetime.combine(d.date(), d.time(), d.tzinfo)。 如果 date 是 datetime 对象,则忽略其时间分量和 tzinfo 属性。

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

classmethod datetime.strptime(date_string, format)
返回date_string对应的datetime,按照格式解析。 这相当于 datetime(*(time.strptime(date_string, format)[0:6]))ValueError 如果 date_string 和格式不能被 time.strptime() 解析或者它返回一个不是时间元组的值,则会引发。 有关格式化指令的完整列表,请参阅 strftime() 和 strptime() 行为

类属性:

datetime.min
最早可表示的datetimedatetime(MINYEAR, 1, 1, tzinfo=None)
datetime.max
最新可表示的 datetimedatetime(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
对象作为 tzinfo 参数传递给 datetime 构造函数,或者 None 如果没有传递。
datetime.fold

[0, 1] 中。 用于在重复间隔期间消除墙壁时间的歧义。 (当时钟在夏令时结束时回滚或当前区域的 UTC 偏移量因政治原因减少时,会出现重复间隔。)值 0 (1) 表示两个时刻中较早(较晚)的时刻相同的墙壁时间表示。

3.6 版中的新功能。

支持的操作:

手术 结果
datetime2 = datetime1 + timedelta (1)
datetime2 = datetime1 - timedelta (2)
timedelta = datetime1 - datetime2 (3)
datetime1 < datetime2 datetimedatetime 进行比较。 (4)
  1. datetime2 是从 datetime1 中删除的 timedelta 的持续时间,如果timedelta.days > 0,或向后,如果timedelta.days < 0。 结果具有与输入日期时间相同的 tzinfo 属性,并且后面有 datetime2 - datetime1 == timedelta。 如果 datetime2.year 小于 MINYEAR 或大于 MAXYEAR,则会引发 OverflowError。 请注意,即使输入是感知对象,也不会进行时区调整。

  2. 计算 datetime2 使得 datetime2 + timedelta == datetime1。 至于加法,结果与输入日期时间具有相同的 tzinfo 属性,即使输入知道也不会进行时区调整。

  3. datetime 减去 datetime 仅在两个操作数都是朴素的或两者都知道时才定义。 如果一个人知道而另一个人天真,则会引发 TypeError

    如果两者都是幼稚的,或者两者都知道并且具有相同的 tzinfo 属性,则忽略 tzinfo 属性,结果是一个 timedelta 对象 t 使得 datetime2 + t == datetime1。 在这种情况下不进行时区调整。

    如果两者都知道并且具有不同的 tzinfo 属性,则 a-b 的行为就像首先将 ab 首先转换为朴素的 UTC 日期时间一样。 结果是 (a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset()),只是实现永远不会溢出。

  4. datetime1 在时间上先于 datetime2 时,datetime1 被认为小于 datetime2

    如果一个比较是天真的而另一个知道,则在尝试进行订单比较时会引发 TypeError。 对于相等比较,朴素实例永远不等于有意识的实例。

    如果两个比较数都知道,并且具有相同的 tzinfo 属性,则公共 tzinfo 属性将被忽略并比较基准日期时间。 如果两个比较数都知道并且具有不同的 tzinfo 属性,则首先通过减去它们的 UTC 偏移量(从 self.utcoffset() 获得)来调整比较数。

    3.3 版更改: 天真和感知 datetime 实例之间的相等比较不会引发 TypeError

    笔记

    为了阻止比较返回到比较对象地址的默认方案,如果另一个比较对象不是 datetime 对象,则日期时间比较通常会引发 TypeError。 但是,如果另一个比较对象具有 timetuple() 属性,则会返回 NotImplemented。 这个钩子为其他类型的日期对象提供了实现混合类型比较的机会。 如果不是,当 datetime 对象与不同类型的对象进行比较时,除非比较是 ==!=,否则会引发 TypeError。 后一种情况分别返回 FalseTrue

datetime 对象可以用作字典键。 在布尔上下文中,所有 datetime 对象都被认为是 true。

实例方法:

datetime.date()
返回具有相同年月日的 date 对象。
datetime.time()

返回具有相同时、分、秒、微秒和折叠的 time 对象。 tzinfoNone。 另见方法 timetz()

3.6 版更改: 折叠值复制到返回的 time 对象。

datetime.timetz()

返回具有相同小时、分钟、秒、微秒、折叠和 tzinfo 属性的 time 对象。 另见方法 time()

3.6 版更改: 折叠值复制到返回的 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)

返回具有相同属性的日期时间,除了那些由指定的关键字参数赋予新值的属性。 请注意,可以指定 tzinfo=None 以从已知日期时间创建一个简单的日期时间,而无需转换日期和时间数据。

3.6 新功能: 添加 fold 参数。

datetime.astimezone(tz=None)

返回具有新的 tzinfo 属性 tzdatetime 对象,调整日期和时间数据,使结果与 self 的 UTC 时间相同,但在 tz 的本地时间。

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

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

如果self.tzinfotzself.astimezone(tz)等于self:不调整日期或时间数据。 否则结果是时区 tz 中的本地时间,表示与 self 相同的 UTC 时间:在 astz = dt.astimezone(tz) 之后,astz - astz.utcoffset() 将具有相同的日期和时间数据为 dt - dt.utcoffset()

如果您只想将时区对象 tz 附加到日期时间 dt 而不调整日期和时间数据,请使用 dt.replace(tzinfo=tz)。 如果您只想从已知日期时间 dt 中删除时区对象而不转换日期和时间数据,请使用 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 time zone 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 对象,表示大小小于一天的整数分钟。
datetime.dst()
如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(self),如果后者不返回 None,则引发异常,或 timedelta 对象,表示大小小于一天的整数分钟。
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() ]返回Nonetm_isdst设置为-1; 否则如果 dst() 返回非零值,则 tm_isdst 设置为 1; 否则 tm_isdst 设置为 0
datetime.utctimetuple()

如果 datetime 实例 d 是 naive,这与 d.timetuple() 相同,除了 tm_isdst 被强制为 0,而不管 d.dst() ] 返回。 DST 永远不会在 UTC 时间生效。

如果 d 知道,d 被归一化为 UTC 时间,通过减去 d.utcoffset(),并返回归一化时间的 time.struct_time . tm_isdst 强制为 0。 请注意,如果 d.year 是 MINYEARMAXYEAR 并且 UTC 调整溢出一年边界,则可能会引发 OverflowError

datetime.toordinal()
返回日期的预测格列高利序数。 与 self.date().toordinal() 相同。
datetime.timestamp()

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

假设 Naive datetime 实例表示本地时间,并且此方法依赖于平台 C mktime() 函数来执行转换。 由于 datetime 在许多平台上支持的值范围比 mktime() 更广,因此此方法可能会在过去或将来很长时间内引发 OverflowError

对于有意识的 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()
返回一个 3 元组,(ISO 年份、ISO 周数、ISO 工作日)。 与 self.date().isocalendar() 相同。
datetime.isoformat(sep='T', timespec='auto')

以 ISO 8601 格式返回表示日期和时间的字符串,YYYY-MM-DDTHH:MM:SS.mmmmmm 或者,如果 microsecond 为 0,则 YYYY-MM-DDTHH:MM:SS

如果 utcoffset() 不返回 None,则附加一个 6 字符的字符串,以(带符号的)小时和分钟给出 UTC 偏移量:YYYY-MM-DDTHH:MM:SS。 mmmmmm+HH:MM 或者,如果 microsecond 是 0 YYYY-MM-DDTHH:MM:SS+HH:MM

可选参数 sep(默认为 'T')是一个单字符分隔符,位于结果的日期和时间部分之间。 例如,

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'

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

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

  • 'hours':包括两位 HH 格式的 hour

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

  • 'seconds':包括小时分钟的HH:MM:SS格式。

  • 'milliseconds':包括全时,但将小数秒部分截断为毫秒。 HH:MM:SS.sss 格式。

  • 'microseconds':以 HH:MM:SS.mmmmmm 格式包括全职。

笔记

排除的时间分量被截断,而不是四舍五入。

ValueError 将在无效的 timespec 参数上引发。

>>> 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()
返回表示日期和时间的字符串,例如 datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec  4 20:30:40 2002'd.ctime() 在本机 C ctime() 函数(time.ctime() 调用,但 datetime. ctime() 不调用) 符合 C 标准。
datetime.strftime(format)
返回一个表示日期和时间的字符串,由显式格式字符串控制。 有关格式化指令的完整列表,请参阅 strftime() 和 strptime() 行为
datetime.__format__(format)
datetime.strftime() 相同。 这使得可以在 格式化字符串文字 和使用 str.format() 时为 datetime 对象指定格式字符串。 有关格式化指令的完整列表,请参阅 strftime() 和 strptime() 行为

使用日期时间对象的示例:

>>> from datetime import datetime, date, time
>>> # 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() or datetime.utcnow()
>>> datetime.now()   
datetime.datetime(2007, 12, 6, 16, 29, 43, 79043)   # GMT +1
>>> datetime.utcnow()   
datetime.datetime(2007, 12, 6, 15, 29, 43, 79060)
>>> # 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 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 一起使用:

>>> from datetime import timedelta, datetime, tzinfo
>>> class GMT1(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=1) + self.dst(dt)
...     def dst(self, dt):
...         # DST starts last Sunday in March
...         d = datetime(dt.year, 4, 1)   # ends last Sunday in October
...         self.dston = d - timedelta(days=d.weekday() + 1)
...         d = datetime(dt.year, 11, 1)
...         self.dstoff = d - timedelta(days=d.weekday() + 1)
...         if self.dston <=  dt.replace(tzinfo=None) < self.dstoff:
...             return timedelta(hours=1)
...         else:
...             return timedelta(0)
...     def tzname(self,dt):
...          return "GMT +1"
...
>>> class GMT2(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=2) + self.dst(dt)
...     def dst(self, dt):
...         d = datetime(dt.year, 4, 1)
...         self.dston = d - timedelta(days=d.weekday() + 1)
...         d = datetime(dt.year, 11, 1)
...         self.dstoff = d - timedelta(days=d.weekday() + 1)
...         if self.dston <=  dt.replace(tzinfo=None) < self.dstoff:
...             return timedelta(hours=1)
...         else:
...             return timedelta(0)
...     def tzname(self,dt):
...         return "GMT +2"
...
>>> gmt1 = GMT1()
>>> # Daylight Saving Time
>>> dt1 = datetime(2006, 11, 21, 16, 30, tzinfo=gmt1)
>>> dt1.dst()
datetime.timedelta(0)
>>> dt1.utcoffset()
datetime.timedelta(0, 3600)
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=gmt1)
>>> dt2.dst()
datetime.timedelta(0, 3600)
>>> dt2.utcoffset()
datetime.timedelta(0, 7200)
>>> # Convert datetime to another time zone
>>> dt3 = dt2.astimezone(GMT2())
>>> dt3     
datetime.datetime(2006, 6, 14, 14, 0, tzinfo=<GMT2 object at 0x...>)
>>> dt2     
datetime.datetime(2006, 6, 14, 13, 0, tzinfo=<GMT1 object at 0x...>)
>>> dt2.utctimetuple() == dt3.utctimetuple()
True

8.1.5. 时间对象

时间对象表示一天中的(本地)时间,独立于任何特定的一天,并且可以通过 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(0, 0, 0, 0)
time.max
最新可表示的 timetime(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
该对象作为 tzinfo 参数传递给 time 构造函数,或者 None 如果没有传递。
time.fold

[0, 1] 中。 用于在重复间隔期间消除墙壁时间的歧义。 (当时钟在夏令时结束时回滚或当前区域的 UTC 偏移量因政治原因减少时,会出现重复间隔。)值 0 (1) 表示两个时刻中较早(较晚)的时刻相同的墙壁时间表示。

3.6 版中的新功能。

支持的操作:

  • timetime 的比较,其中 a 被认为小于 bab 之前 及时。 如果一个比较是天真的而另一个知道,则在尝试进行订单比较时会引发 TypeError。 对于相等比较,朴素实例永远不等于有意识的实例。

    如果两个比较数都知道,并且具有相同的 tzinfo 属性,则忽略公共的 tzinfo 属性并比较基准时间。 如果两个比较数都知道并且具有不同的 tzinfo 属性,则首先通过减去它们的 UTC 偏移量(从 self.utcoffset() 获得)来调整比较数。 为了阻止混合类型比较返回到按对象地址进行的默认比较,当 time 对象与不同类型的对象进行比较时,会引发 TypeError,除非比较是 ==!=。 后一种情况分别返回 FalseTrue

    3.3 版更改: 天真和感知 时间 实例之间的平等比较不会引发 TypeError

  • 哈希,用作字典键

  • 高效酸洗

在布尔上下文中,一个 time 对象总是被认为是真的。

3.5 版更改: 在 Python 3.5 之前,如果 time 对象在 UTC 中表示午夜,则它被认为是假的。 这种行为被认为是晦涩难懂且容易出错的,并已在 Python 3.5 中删除。 有关完整详细信息,请参阅 :issue:`13936`


实例方法:

time.replace(hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, * fold=0)

返回具有相同值的 time,除了那些由指定的关键字参数赋予新值的属性。 请注意,可以指定 tzinfo=None 以从感知 time 创建一个朴素的 time,而无需转换时间数据。

3.6 新功能: 添加 fold 参数。

time.isoformat(timespec='auto')

以 ISO 8601 格式返回表示时间的字符串,HH:MM:SS.mmmmmm 或者,如果 microsecond 为 0,则 HH:MM:SS 如果 utcoffset() 不返回 [ X157X],附加一个 6 个字符的字符串,以(带符号的)小时和分钟给出 UTC 偏移量:HH:MM:SS.mmmmmm+HH:MM 或者,如果 self.microsecond 为 0,则 HH:MM: SS+HH:MM

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

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

  • 'hours':包括两位 HH 格式的 hour

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

  • 'seconds':包括小时分钟的HH:MM:SS格式。

  • 'milliseconds':包括全时,但将小数秒部分截断为毫秒。 HH:MM:SS.sss 格式。

  • 'microseconds':以 HH:MM:SS.mmmmmm 格式包括全职。

笔记

排除的时间分量被截断,而不是四舍五入。

ValueError 将在无效的 timespec 参数上引发。

>>> 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.__format__(format)
time.strftime() 相同。 这使得可以在 格式化字符串文字 和使用 str.format() 时为 time 对象指定格式字符串。 有关格式化指令的完整列表,请参阅 strftime() 和 strptime() 行为
time.utcoffset()
如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.utcoffset(None),如果后者不返回 None,则引发异常或一个 timedelta 对象,表示大小小于一天的整数分钟。
time.dst()
如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(None),如果后者不返回 None,则引发异常,或 timedelta 对象,表示大小小于一天的整数分钟。
time.tzname()
如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.tzname(None),如果后者不返回 None,则引发异常或字符串对象。

例子:

>>> from datetime import time, tzinfo, timedelta
>>> class GMT1(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=1)
...     def dst(self, dt):
...         return timedelta(0)
...     def tzname(self,dt):
...         return "Europe/Prague"
...
>>> t = time(12, 10, 30, tzinfo=GMT1())
>>> t                               
datetime.time(12, 10, 30, tzinfo=<GMT1 object at 0x...>)
>>> gmt = GMT1()
>>> t.isoformat()
'12:10:30+01:00'
>>> t.dst()
datetime.timedelta(0)
>>> t.tzname()
'Europe/Prague'
>>> t.strftime("%H:%M:%S %Z")
'12:10:30 Europe/Prague'
>>> 'The {} is {:%H:%M}.'.format("time", t)
'The time is 12:10.'

8.1.6. 资讯对象

class datetime.tzinfo

这是一个抽象基类,这意味着不应直接实例化此类。 您需要派生一个具体的子类,并且(至少)提供您使用的 datetime 方法所需的标准 tzinfo 方法的实现。 datetime 模块提供了一个简单的具体子类 tzinfo, timezone,可以表示与 UTC 有固定偏移的时区,例如 UTC 本身或北美 EST 和 EDT .

tzinfo(的具体子类)的实例可以传递给 datetimetime 对象的构造函数。 后者将它们的属性视为本地时间,而 tzinfo 对象支持显示本地时间与 UTC 的偏移量、时区名称和 DST 偏移量的方法,所有这些都与日期或时间相关对象传递给他们。

酸洗的特殊要求:tzinfo 子类必须有一个 __init__() 方法,可以不带参数调用,否则它可以被酸洗,但可能不会再次被取消酸洗。 这是一项技术要求,未来可能会放宽。

tzinfo 的具体子类可能需要实现以下方法。 究竟需要哪些方法取决于感知 datetime 对象的用途。 如果有疑问,只需实现所有这些。

tzinfo.utcoffset(dt)

返回本地时间与 UTC 的偏移量,以 UTC 以东的分钟数为单位。 如果当地时间在 UTC 以西,这应该是负数。 请注意,这是与 UTC 的总偏移量; 例如,如果 tzinfo 对象同时表示时区和 DST 调整,则 utcoffset() 应返回它们的总和。 如果 UTC 偏移量未知,则返回 None。 否则返回的值必须是一个 timedelta 对象,它指定了 -1439 到 1439 范围内的整数分钟数(1440 = 24*60;偏移量必须小于一天)。 utcoffset() 的大多数实现可能看起来像这两个之一:

return CONSTANT                 # fixed-offset class
return CONSTANT + self.dst(dt)  # daylight-aware class

如果 utcoffset() 不返回 Nonedst() 也不应该返回 None

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

tzinfo.dst(dt)

返回夏令时 (DST) 调整,以 UTC 以东的分钟数为单位,如果 DST 信息未知,则返回 None。 如果 DST 无效,则返回 timedelta(0)。 如果 DST 有效,则将偏移量作为 timedelta 对象返回(有关详细信息,请参阅 utcoffset())。 请注意,如果适用,DST 偏移量已添加到 utcoffset() 返回的 UTC 偏移量中,因此除非您有兴趣获得,否则无需咨询 dst()单独的夏令时信息。 例如, datetime.timetuple() 调用其 tzinfo 属性的 dst() 方法来确定应如何设置 tm_isdst 标志,以及tzinfo.fromutc() 调用 dst() 来解释跨时区时 DST 的变化。

tzinfo 子类的实例 tz 对标准时间和日光时间进行建模在这个意义上必须是一致的:

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

必须为每个 datetime dtdt.tzinfo == tz 返回相同的结果对于正常的 tzinfo 子类,此表达式产生时区的“标准偏移量”,这不应该取决于日期或时间,而只取决于地理位置。 datetime.astimezone()的实现依赖于此,但无法检测违规; 程序员有责任确保它。 如果 tzinfo 子类不能保证这一点,它可能能够覆盖 tzinfo.fromutc() 的默认实现,以便与 astimezone() 一起正常工作。

dst() 的大多数实现可能看起来像这两个之一:

def dst(self, dt):
    # a fixed-offset class:  doesn't account for DST
    return timedelta(0)

或者

def dst(self, dt):
    # Code to set dston and dstoff to the time zone's DST
    # transition times based on the input dt.year, and expressed
    # in standard local time.  Then

    if dston <= dt.replace(tzinfo=None) < dstoff:
        return timedelta(hours=1)
    else:
        return timedelta(0)

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

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 子类的方法应准备好接受 None 或类 datetimedt 参数。

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() 实现。 它足够强大,可以处理固定偏移时区,以及同时考虑标准时间和夏令时的时区,后者即使 DST 过渡时间在不同年份有所不同。 默认 fromutc() 实现可能无法在所有情况下正确处理的时区示例是标准偏移量(来自 UTC)取决于经过的特定日期和时间,这可能出于政治原因而发生. astimezone()fromutc() 的默认实现可能不会产生您想要的结果,如果结果是跨越标准偏移量变化那一刻的小时之一。

跳过错误情况的代码,默认的 fromutc() 实现如下:

def fromutc(self, dt):
    # raise ValueError error if dt.tzinfo is not self
    dtoff = dt.utcoffset()
    dtdst = dt.dst()
    # raise ValueError if dtoff is None or dtdst is None
    delta = dtoff - dtdst  # this is self's standard offset
    if delta:
        dt += delta   # convert to standard local time
        dtdst = dt.dst()
        # raise ValueError if dtdst is None
    if dtdst:
        return dt + dtdst
    else:
        return dt

示例 tzinfo 类:

from datetime import tzinfo, timedelta, datetime, timezone

ZERO = timedelta(0)
HOUR = timedelta(hours=1)
SECOND = timedelta(seconds=1)

# A class capturing the platform's idea of local time.
# (May result in wrong values on historical times in
#  timezones where UTC offset and/or the DST rules had
#  changed in the past.)
import time as _time

STDOFFSET = timedelta(seconds = -_time.timezone)
if _time.daylight:
    DSTOFFSET = timedelta(seconds = -_time.altzone)
else:
    DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):

    def fromutc(self, dt):
        assert dt.tzinfo is self
        stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND
        args = _time.localtime(stamp)[:6]
        dst_diff = DSTDIFF // SECOND
        # Detect fold
        fold = (args == _time.localtime(stamp - dst_diff))
        return datetime(*args, microsecond=dt.microsecond,
                        tzinfo=self, fold=fold)

    def utcoffset(self, dt):
        if self._isdst(dt):
            return DSTOFFSET
        else:
            return STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return DSTDIFF
        else:
            return ZERO

    def tzname(self, dt):
        return _time.tzname[self._isdst(dt)]

    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, 0)
        stamp = _time.mktime(tt)
        tt = _time.localtime(stamp)
        return tt.tm_isdst > 0

Local = LocalTimezone()


# A complete implementation of current DST rules for major US time zones.

def first_sunday_on_or_after(dt):
    days_to_go = 6 - dt.weekday()
    if days_to_go:
        dt += timedelta(days_to_go)
    return dt


# US DST Rules
#
# This is a simplified (i.e., wrong for a few cases) set of rules for US
# DST start and end times. For a complete and up-to-date set of DST rules
# and timezone definitions, visit the Olson Database (or try pytz):
# http://www.twinsun.com/tz/tz-link.htm
# http://sourceforge.net/projects/pytz/ (might not be up-to-date)
#
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1, 3, 8, 2)
# and ends at 2am (DST time) on the first Sunday of Nov.
DSTEND_2007 = datetime(1, 11, 1, 2)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
# Sunday in April and to end at 2am (DST time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
DSTEND_1987_2006 = datetime(1, 10, 25, 2)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
# Sunday in April (the one on or after April 24) and to end at 2am (DST time)
# on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006

def us_dst_range(year):
    # Find start and end times for US DST. For years before 1967, return
    # start = end for no DST.
    if 2006 < year:
        dststart, dstend = DSTSTART_2007, DSTEND_2007
    elif 1986 < year < 2007:
        dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
    elif 1966 < year < 1987:
        dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
    else:
        return (datetime(year, 1, 1), ) * 2

    start = first_sunday_on_or_after(dststart.replace(year=year))
    end = first_sunday_on_or_after(dstend.replace(year=year))
    return start, end


class USTimeZone(tzinfo):

    def __init__(self, hours, reprname, stdname, dstname):
        self.stdoffset = timedelta(hours=hours)
        self.reprname = reprname
        self.stdname = stdname
        self.dstname = dstname

    def __repr__(self):
        return self.reprname

    def tzname(self, dt):
        if self.dst(dt):
            return self.dstname
        else:
            return self.stdname

    def utcoffset(self, dt):
        return self.stdoffset + self.dst(dt)

    def dst(self, dt):
        if dt is None or dt.tzinfo is None:
            # An exception may be sensible here, in one or both cases.
            # It depends on how you want to treat them.  The default
            # fromutc() implementation (called by the default astimezone()
            # implementation) passes a datetime with dt.tzinfo is self.
            return ZERO
        assert dt.tzinfo is self
        start, end = us_dst_range(dt.year)
        # Can't compare naive to aware objects, so strip the timezone from
        # dt first.
        dt = dt.replace(tzinfo=None)
        if start + HOUR <= dt < end - HOUR:
            # DST is in effect.
            return HOUR
        if end - HOUR <= dt < end:
            # Fold (an ambiguous hour): use dt.fold to disambiguate.
            return ZERO if dt.fold else HOUR
        if start <= dt < start + HOUR:
            # Gap (a non-existent hour): reverse the fold rule.
            return HOUR if dt.fold else ZERO
        # DST is off.
        return ZERO

    def fromutc(self, dt):
        assert dt.tzinfo is self
        start, end = us_dst_range(dt.year)
        start = start.replace(tzinfo=self)
        end = end.replace(tzinfo=self)
        std_time = dt + self.stdoffset
        dst_time = std_time + HOUR
        if end <= dst_time < end + HOUR:
            # Repeated hour
            return std_time.replace(fold=1)
        if std_time < start or dst_time >= end:
            # Standard time
            return std_time
        if start <= std_time < end - HOUR:
            # Daylight saving time
            return dst_time


Eastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
Central  = USTimeZone(-6, "Central",  "CST", "CDT")
Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
Pacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")

请注意,在 DST 过渡点,tzinfo 子类中每年有两次不可避免的微妙之处,既考虑了标准时间,也考虑了夏令时。 为具体起见,请考虑美国东部时间 (UTC -0500),其中 EDT 在 3 月的第二个星期日的 1:59 (EST) 之后的分钟开始,并在 11 月的第一个星期日的 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 开始时(“开始”行),本地挂钟从 1:59 跳到 3:00。 当天形式为 2:MM 的挂墙时间实际上没有意义,因此 astimezone(Eastern) 不会在 DST 开始当天提供 hour == 2 的结果。 例如,在 2016 年的 Spring forward transition 时,我们得到

>>> u0 = datetime(2016, 3, 13, 5, tzinfo=timezone.utc)
>>> for i in range(4):
...     u = u0 + i*HOUR
...     t = u.astimezone(Eastern)
...     print(u.time(), 'UTC =', t.time(), t.tzname())
...
05:00:00 UTC = 00:00:00 EST
06:00:00 UTC = 01:00:00 EST
07:00:00 UTC = 03:00:00 EDT
08:00:00 UTC = 04:00:00 EDT

当 DST 结束(“结束”行)时,可能会出现一个更糟糕的问题:在当地的挂钟时间中,有一个小时无法明确拼写:夏令时的最后一个小时。 在东部,这是日光时间结束时 5:MM UTC 形式的时间。 当地挂钟再次从 1:59(白天时间)跳回到 1:00(标准时间)。 1:MM 形式的本地时间是不明确的。 astimezone() 通过将两个相邻的 UTC 小时映射到同一个本地小时来模拟本地时钟的行为。 在东部示例中,格式为 5:MM 和 6:MM 的 UTC 时间在转换为东部时都映射为 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个小时))。

也可以看看

日期工具.tz

标准库有 timezone 类用于处理与 UTC 和 timezone.utc 作为 UTC 时区实例的任意固定偏移量。

dateutil.tz 库将 IANA 时区数据库 (也称为 Olson 数据库)引入 Python,推荐使用。

IANA 时区数据库

时区数据库(通常称为 tz、tzdata 或 zoneinfo)包含代表全球许多代表性位置的本地时间历史的代码和数据。 它会定期更新,以反映政治机构对时区边界、UTC 偏移量和夏令时规则所做的更改。


8.1.7. 时区对象

timezone 类是 tzinfo 的子类,它的每个实例都代表一个由 UTC 固定偏移量定义的时区。 请注意,此类的对象不能用于表示一年中不同日期使用不同偏移量或对民用时间进行历史更改的位置的时区信息。

class datetime.timezone(offset, name=None)

offset 参数必须指定为 timedelta 对象,表示本地时间和 UTC 之间的差异。 它必须严格介于 -timedelta(hours=24)timedelta(hours=24) 之间并表示整数分钟,否则会引发 ValueError

name 参数是可选的。 如果指定,它必须是一个字符串,将用作 datetime.tzname() 方法返回的值。

3.2 版中的新功能。

timezone.utcoffset(dt)
返回构造 timezone 实例时指定的固定值。 dt 参数被忽略。 返回值是一个 timedelta 实例,等于本地时间和 UTC 之间的差异。
timezone.tzname(dt)

返回构造 timezone 实例时指定的固定值。 如果构造函数中未提供 name,则 tzname(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))


8.1.8. strftime()和strptime()行为

datedatetimetime对象都支持strftime(format)方法,在显式格式控制下创建表示时间的字符串细绳。 从广义上讲,d.strftime(fmt) 的作用类似于 time 模块的 time.strftime(fmt, d.timetuple()),尽管并非所有对象都支持 timetuple() 方法。

相反,datetime.strptime() 类方法从表示日期和时间的字符串以及相应的格式字符串创建一个 datetime 对象。 datetime.strptime(date_string, format) 等价于 datetime(*(time.strptime(date_string, format)[0:6])),除非格式包含亚秒分量或时区偏移信息,datetime.strptime 支持但被 time.strptime 丢弃.

对于 time 对象,不应使用年、月和日的格式代码,因为时间对象没有这些值。 如果无论如何都使用它们,则用 1900 代替年,用 1 代替月和日。

对于 date 对象,不应使用小时、分钟、秒和微秒的格式代码,因为 date 对象没有这些值。 如果无论如何都使用它们,0 将替换它们。

支持的全套格式代码因平台而异,因为 Python 调用了平台 C 库的 strftime() 函数,平台变异是常见的。 要查看您的平台支持的完整格式代码集,请参阅 strftime(3) 文档。

以下是 C 标准(1989 版)要求的所有格式代码的列表,这些代码适用于具有标准 C 实现的所有平台。 请注意,C 标准的 1999 版本添加了额外的格式代码。

指示 意义 例子 笔记
%a 工作日作为语言环境的缩写名称。

周日、周一、...、周六(en_US);

所以,Mo,...,Sa (de_DE)

(1)
%A 工作日作为语言环境的全名。

星期日、星期一、……、星期六(en_US);

Sonntag, Montag, ..., Samstag (de_DE)

(1)
%w 工作日为十进制数,其中 0 是星期日,6 是星期六。 0, 1, ..., 6
%d 以零填充的十进制数表示的月份中的某天。 01, 02, …, 31
%b 月份作为语言环境的缩写名称。

一月、二月、...、十二月(en_US);

一月,二月,...,德兹(de_DE)

(1)
%B 月份作为语言环境的全名。

一月、二月、……、十二月(en_US);

一月、二月、...、十二月 (de_DE)

(1)
%m 以零填充的十进制数表示的月份。 01, 02, …, 12
%y 没有世纪的年份作为零填充的十进制数。 00, 01, …, 99
%Y 以世纪为十进制数的年份。 0001, 0002, ..., 2013, 2014, ..., 9998, 9999 (2)
%H 小时(24 小时制)作为补零的十进制数。 00, 01, …, 23
%I 小时(12 小时制)作为用零填充的十进制数。 01, 02, …, 12
%p 区域设置相当于 AM 或 PM。

上午、下午(en_US);

上午,下午(de_DE)

(1), (3)
%M 分钟作为用零填充的十进制数。 00, 01, …, 59
%S 第二个是用零填充的十进制数。 00, 01, …, 59 (4)
%f 微秒为十进制数,左侧补零。 000000, 000001, ..., 999999 (5)
%z +HHMM 或 -HHMM 形式的 UTC 偏移量(如果对象是幼稚的,则为空字符串)。 (空)、+0000、-0400、+1030 (6)
%Z 时区名称(如果对象是幼稚的,则为空字符串)。 (空)、UTC、EST、CST
%j 以零填充的十进制数表示的一年中的第几天。 001, 002, …, 366
%U 一年中的周数(星期日作为一周的第一天)作为零填充的十进制数。 新年第一个星期日之前的所有日子都被视为第 0 周。 00, 01, …, 53 (7)
%W 以十进制数表示的一年中的周数(星期一为一周的第一天)。 新年中第一个星期一之前的所有日子都被视为第 0 周。 00, 01, …, 53 (7)
%c 区域设置的适当日期和时间表示。

1988 年 8 月 16 日星期二 21:30:00(en_US);

1988 年 8 月 16 日 21:30:00 (de_DE)

(1)
%x 区域设置的适当日期表示。

88 年 8 月 16 日(无);

1988 年 8 月 16 日(en_US);

16.08.1988 (de_DE)

(1)
%X 区域设置的适当时间表示。

21:30:00(en_US);

21:30:00 (de_DE)

(1)
%% 文字 '%' 字符。 %

为方便起见,包含了 C89 标准不需要的几个附加指令。 这些参数都对应于 ISO 8601 日期值。 当与 strftime() 方法一起使用时,这些可能不适用于所有平台。 ISO 8601 年和 ISO 8601 周指令不能与上述年份和周数指令互换。 使用不完整或不明确的 ISO 8601 指令调用 strptime() 将引发 ValueError

指示 意义 例子 笔记
%G ISO 8601 年,世纪代表包含 ISO 周大部分时间的年份 (%V)。 0001, 0002, ..., 2013, 2014, ..., 9998, 9999 (8)
%u ISO 8601 工作日为十进制数,其中 1 是星期一。 1, 2, ..., 7
%V ISO 8601 周为十进制数,星期一为一周的第一天。 第 1 周是包含 1 月 4 日的那一周。 01, 02, …, 53 (8)

3.6 新功能:添加了 %G%u%V


笔记:

  1. 因为格式取决于当前的语言环境,所以在对输出值进行假设时应该小心。 字段顺序会有所不同(例如,“月/日/年”与“日/月/年”),并且输出可能包含使用区域设置的默认编码的 Unicode 字符(例如,如果当前区域设置为 ja_JP,默认编码可以是eucJPSJISutf-8中的任何一种;使用locale.getlocale()确定当前语言环境的编码)。

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

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

    3.3 版更改: 在 3.2 版中,strftime() 方法被限制为年数 >= 1000。

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

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

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

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

    对于有意识的对象:

    %z

    utcoffset() 转换为 +HHMM 或 -HHMM 形式的 5 个字符的字符串,其中 HH 是给出 UTC 偏移小时数的 2 位字符串,MM 是给出数字的 2 位字符串UTC 偏移分钟数。 例如,如果 utcoffset() 返回 timedelta(hours=-3, minutes=-30),则 %z 被替换为字符串 '-0330'

    %Z

    如果 tzname() 返回 None,则 %Z 被替换为空字符串。 否则 %Z 被返回值替换,该值必须是一个字符串。

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

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

  8. %U%W 类似,%V 仅用于在 [ X148X] 格式字符串。 另请注意,%G%Y 不可互换。

脚注

1
如果,也就是说,我们忽略相对论的影响