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

腳註