新聞中心
在日常生活中,我們可以用多種不同的格式來(lái)表示日期和時(shí)間,例如,7 月 4 日、2022 年 3 月 8 日、22:00 或 2022 年 12 月 31 日 23:59:59。它們使用整數(shù)和字符串的組合,或者也可以使用浮點(diǎn)數(shù)來(lái)表示一天、一分鐘等等,各種各樣的時(shí)間表示方式,確實(shí)讓人眼花繚亂。

不過(guò)還好,Python 有 datetime 模塊,它允許我們輕松地操作表示日期和時(shí)間的對(duì)象。
在今天的文章中,我們將學(xué)習(xí)以下內(nèi)容:
- Python 中 datetime 模塊的使用
- 使用 Python 日期時(shí)間函數(shù)將字符串轉(zhuǎn)換為日期時(shí)間對(duì)象,反之亦然
- 從日期時(shí)間對(duì)象中提取日期和時(shí)間
- 使用時(shí)間戳
- 對(duì)日期和時(shí)間執(zhí)行算術(shù)運(yùn)算
- 使用時(shí)區(qū)
- 創(chuàng)建一個(gè)倒數(shù)計(jì)時(shí)器來(lái)確定距離 2023 年新年還有多長(zhǎng)時(shí)間
Let's do it!
如何在 Python 中使用日期時(shí)間
正如我們之前所看到的,在編程中表示日期和時(shí)間是一項(xiàng)非常有挑戰(zhàn)的事情。首先,我們必須以標(biāo)準(zhǔn)的、普遍接受的格式來(lái)表示它們。幸運(yùn)的是,國(guó)際標(biāo)準(zhǔn)化組織 (ISO) 制定了一個(gè)全球標(biāo)準(zhǔn) ISO 8601,它將與日期和時(shí)間相關(guān)的對(duì)象表示為 YYYY-MM-DD HH:MM:SS,其信息范圍從最重要的(年,YYYY)到 最不重要的(秒,SS)。這種格式的每一部分都表示為一個(gè)四位數(shù)或兩位數(shù)。
Python 中的 datetime 模塊有 5 個(gè)主要類(模塊的一部分):
- date 操作日期對(duì)象
- time 操作時(shí)間對(duì)象
- datetime 是日期和時(shí)間的組合
- timedelta 允許我們使用時(shí)間區(qū)間
- tzinfo 允許我們使用時(shí)區(qū)
此外,我們將使用 zoneinfo 模塊,它為我們提供了一種處理時(shí)區(qū)的更加現(xiàn)代的方式,以及 dateutil 包,它包含許多有用的函數(shù)來(lái)處理日期和時(shí)間。
讓我們導(dǎo)入 datetime 模塊并創(chuàng)建我們的第一個(gè)日期和時(shí)間對(duì)象:
# From the datetime module import date
from datetime import date
# Create a date object of 2000-02-03
date(2022, 2, 3)
Output:
datetime.date(2022, 2, 3)
在上面的代碼中,我們從模塊中導(dǎo)入了日期類,然后創(chuàng)建了 2022 年 2 月 3 日的 datetime.date 對(duì)象。需要注意的是,用于創(chuàng)建該對(duì)象的數(shù)字順序與 ISO 8061 中的完全相同 (但我們省略了 0 并且只寫(xiě)了一個(gè)數(shù)字的月份和日期)。
關(guān)于時(shí)間的編碼都是基于現(xiàn)實(shí)的,所以假設(shè)我們要?jiǎng)?chuàng)建一個(gè) 2000-26-03 的對(duì)象:
# Create a date object of 2000-26-03
date(2000, 26, 3)
Output:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [2], in
1 # Create a date object of 2000-26-03
----> 2 date(2000, 26, 3)
ValueError: month must be in 1..12
我們得到 ValueError: month must be in 1..12,毫無(wú)疑問(wèn),日歷中沒(méi)有第 26 個(gè)月,拋出異常。
讓我們看看如何創(chuàng)建一個(gè) datetime.time 對(duì)象:
# From the datetime module import time
from datetime import time
# Create a time object of 05:35:02
time(5, 35, 2)
Output:
datetime.time(5, 35, 2)
現(xiàn)在,如果我們想要在一個(gè)對(duì)象中同時(shí)包含日期和時(shí)間怎么辦?我們應(yīng)該使用 datetime 類:
# From the datetime module import datetime
from datetime import datetime
# Create a datetime object of 2000-02-03 05:35:02
datetime(2000, 2, 3, 5, 35, 2)
Output:
datetime.datetime(2000, 2, 3, 5, 35, 2)
不出意外,我們成功創(chuàng)建了 datetime 對(duì)象。我們還可以更明確地將關(guān)鍵字參數(shù)傳遞給 datetime 構(gòu)造函數(shù):
datetime(year=2000, month=2, day=3, hour=5, minute=35, second=2)
Output:
datetime.datetime(2000, 2, 3, 5, 35, 2)
如果我們只傳入三個(gè)參數(shù)(年、月和日)會(huì)怎樣,是否會(huì)報(bào)錯(cuò)呢
# Create a datetime object of 2000-02-03
datetime(2000, 2, 3)
Output:
datetime.datetime(2000, 2, 3, 0, 0)
我們可以看到,現(xiàn)在對(duì)象中有兩個(gè)零(分別代表)小時(shí)和分鐘。同時(shí)秒數(shù)也被省略了。
在許多情況下,我們想知道當(dāng)前的確切時(shí)間??梢允褂?datetime 類的 now() 方法:
# Time at the moment
now = datetime.now()
now
Output:
datetime.datetime(2022, 8, 1, 0, 9, 39, 611254)
我們得到一個(gè)日期時(shí)間對(duì)象,這里最后一個(gè)數(shù)字是微秒。
如果我們只需要今天的日期,我們可以使用 date 類的 today() 方法:
today = date.today()
today
Output:
datetime.date(2022, 8, 1)
如果我們只需要時(shí)間,就必須訪問(wèn) datetime.now() 對(duì)象的小時(shí)、分鐘和秒屬性,并將它們傳遞給時(shí)間構(gòu)造函數(shù):
time(now.hour, now.minute, now.second)
Output:
datetime.time(11, 33, 25)
我們還可以使用 isocalendar() 函數(shù)從日期時(shí)間對(duì)象中提取周數(shù)和天數(shù)。它將返回一個(gè)包含 ISO 年份、周數(shù)和工作日數(shù)的三項(xiàng)元組:
# isocalendar() returns a 3-item tuple with ISO year, week number, and weekday number
now.isocalendar()
Output:
datetime.IsoCalendarDate(year=2022, week=7, weekday=1)
在 ISO 格式中,一周從星期一開(kāi)始,到星期日結(jié)束。一周中的天數(shù)由從 1(星期一)到 7(星期日)的數(shù)字編碼。如果我們想訪問(wèn)這些元組元素之一,需要使用括號(hào)表示法:
# Access week number
week_number = now.isocalendar()[1]
week_number
Output:
7
從字符串中提取日期
在數(shù)據(jù)科學(xué)和一般編程中,我們主要使用以數(shù)十種不同格式存儲(chǔ)為字符串的日期和時(shí)間,具體取決于地區(qū)、公司或我們需要的信息粒度。有時(shí),我們需要日期和確切時(shí)間,但在其他情況下,我們只需要年份和月份。我們?cè)撊绾螐淖址刑崛∥覀冃枰臄?shù)據(jù),以便將其作為日期時(shí)間(日期、時(shí)間)對(duì)象來(lái)操作呢?
fromisoformat() 和 isoformat()
我們學(xué)習(xí)的第一個(gè)將日期字符串轉(zhuǎn)換為日期對(duì)象的函數(shù)是 fromisoformat,我們這樣稱呼它是因?yàn)樗褂?ISO 8601 格式(即 YYYY-MM-DD),讓我們看一個(gè)例子:
# Convert a date string into a date object
date.fromisoformat("2022-12-31")
Output:
datetime.date(2022, 12, 31)
ISO 格式也包含時(shí)間,但如果我們卻不能將它傳遞給函數(shù):
date.fromisoformat("2022-12-31 00:00:00")Output:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [13], in
----> 1 date.fromisoformat("2022-12-31 00:00:00")
ValueError: Invalid isoformat string: '2022-12-31 00:00:00'
當(dāng)然,我們也可以進(jìn)行逆向運(yùn)算,將 datetime 對(duì)象轉(zhuǎn)換為 ISO 格式的日期字符串,我們應(yīng)該使用 isoformat():
# Convert a datetime object into a string in the ISO format
date(2022, 12, 31).isoformat()
Output:
'2022-12-31'
strptime()
為了解決上述 ValueError 問(wèn)題,我們可以使用 strptime() 函數(shù),該函數(shù)可以將任意日期/時(shí)間字符串轉(zhuǎn)換為日期時(shí)間對(duì)象。我們的字符串不一定需要遵循 ISO 格式,但我們應(yīng)該指定字符串的哪一部分代表哪個(gè)日期或時(shí)間單位(年、小時(shí)等)。讓我們看一個(gè)例子,首先,我們將使用嚴(yán)格的 ISO 格式將字符串轉(zhuǎn)換為日期時(shí)間對(duì)象:
# Date as a string
iso_date = "2022-12-31 23:59:58"
# ISO format
iso_format = "%Y-%m-%d %H:%M:%S"
# Convert the string into a datetime object
datetime.strptime(iso_date, iso_format)
Output:
datetime.datetime(2022, 12, 31, 23, 59, 58)
在第一行,我們創(chuàng)建一個(gè)日期/時(shí)間字符串。在第二行中,我們使用特殊代碼指定字符串的格式,該代碼包含一個(gè)百分號(hào),后跟一個(gè)編碼日期或時(shí)間單位的字符。最后,在第三行中,我們使用 strptime() 函數(shù)將字符串轉(zhuǎn)換為日期時(shí)間對(duì)象。這個(gè)函數(shù)有兩個(gè)參數(shù):字符串和字符串的格式。
我們上面使用的代碼還可以編碼其他日期和時(shí)間單位,如工作日、月份名稱、周數(shù)等。
|
代碼 |
示例 |
說(shuō)明 |
|
%A |
Monday |
完整的工作日名稱 |
|
%B |
December |
全月名稱 |
|
%W |
2 |
周數(shù)(星期一為一周的第一天) |
讓我們?cè)倏磶讉€(gè)使用其他格式的示例:
# European date as a string
european_date = "31-12-2022"
# European format
european_format = "%d-%m-%Y"
# Convert the string into a datetime object
datetime.strptime(european_date, european_format)
Output:
datetime.datetime(2022, 12, 31, 0, 0)
如上所示,字符串已成功轉(zhuǎn)換,但還有額外的零表示時(shí)間字段,讓我們看一個(gè)使用其他代碼的示例:
# Full month name date
full_month_date = "12 September 2022"
# Full month format
full_month_format = "%d %B %Y"
# Convert the string into a datetime object
datetime.strptime(full_month_date, full_month_format)
Output:
datetime.datetime(2022, 9, 12, 0, 0)
還是可以正常轉(zhuǎn)換,但是需要注意的是,我們定義的格式應(yīng)該與日期字符串的格式相匹配。因此,如果我們有空格、冒號(hào)、連字符或其他字符來(lái)分隔時(shí)間單位,那么它們也應(yīng)該在代碼字符串中。否則,Python 將拋出 ValueError:
# Full month name date
full_month_date = "12 September 2022"
# Wrong format (missing space)
full_month_format = "%d%B %Y"
# Convert the string into a datetime object
datetime.strptime(full_month_date, full_month_format)
Output:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [18], in
5 full_month_format = "%d%B %Y"
7 # Convert the string into a datetime object
----> 8 datetime.strptime(full_month_date, full_month_format)
File ~/coding/dataquest/articles/using-the-datetime-package/env/lib/python3.10/_strptime.py:568, in _strptime_datetime(cls, data_string, format)
565 def _strptime_datetime(cls, data_string, format="%a %b %d %H:%M:%S %Y"):
566 """Return a class cls instance based on the input string and the
567 format string."""
--> 568 tt, fraction, gmtoff_fraction = _strptime(data_string, format)
569 tzname, gmtoff = tt[-2:]
570 args = tt[:6] + (fraction,)
File ~/coding/dataquest/articles/using-the-datetime-package/env/lib/python3.10/_strptime.py:349, in _strptime(data_string, format)
347 found = format_regex.match(data_string)
348 if not found:
--> 349 raise ValueError("time data %r does not match format %r" %
350 (data_string, format))
351 if len(data_string) != found.end():
352 raise ValueError("unconverted data remains: %s" %
353 data_string[found.end():])
ValueError: time data '12 September 2022' does not match format '%d%B %Y'
可以看到,即使缺少一個(gè)空格也可能導(dǎo)致錯(cuò)誤!
將日期時(shí)間對(duì)象轉(zhuǎn)換為字符串
strftime()
在 Python 中,我們還可以使用 strftime() 函數(shù)將日期時(shí)間對(duì)象轉(zhuǎn)換為字符串。它有兩個(gè)參數(shù):一個(gè)日期時(shí)間對(duì)象和輸出字符串的格式。
# Create a datetime object
datetime_obj = datetime(2022, 12, 31)
# American date format
american_format = "%m-%d-%Y"
# European format
european_format = "%d-%m-%Y"
# American date string
print(f"American date string: {datetime.strftime(datetime_obj, american_format)}.")
# European date string
print(f"European date string: {datetime.strftime(datetime_obj, european_format)}.")
Output:
American date string: 12-31-2022.
European date string: 31-12-2022.
我們采用相同的日期時(shí)間對(duì)象并將其轉(zhuǎn)換為兩種不同的格式。我們還可以指定其他格式,例如完整的月份名稱后跟日期和年份。
full_month = "%B %d, %Y"
datetime.strftime(datetime_obj, full_month)
Output:
'December 31, 2022'
另一種使用 strftime 的方法是將它放在 datetime 對(duì)象之后:
datetime_obj = datetime(2022, 12, 31, 23, 59, 59)
full_datetime = "%B %d, %Y %H:%M:%S"
datetime_obj.strftime(full_datetime)
Output:
'December 31, 2022 23:59:59'
在實(shí)際使用當(dāng)中,如果我們想提取不同年份 12 月 31 日的工作日名稱,strftime() 可能很方便:
# Extract the weekday name of December 31
weekday_format = "%A"
for year in range(2022, 2026):
print(f"Weekday of December 31, {year} is {date(year, 12, 31).strftime(weekday_format)}.")
Output:
Weekday of December 31, 2022 is Saturday.
Weekday of December 31, 2023 is Sunday.
Weekday of December 31, 2024 is Tuesday.
Weekday of December 31, 2025 is Wednesday.
時(shí)間戳
在編程中,通常會(huì)看到以 Unix 時(shí)間戳格式存儲(chǔ)的日期和時(shí)間,這種格式將任何日期表示為數(shù)字。一般情況時(shí)間戳是從 1970 年 1 月 1 日 00:00:00 UTC(協(xié)調(diào)世界時(shí))開(kāi)始的 Unix 紀(jì)元經(jīng)過(guò)的秒數(shù)。我們可以使用 timestamp() 函數(shù)計(jì)算這個(gè)數(shù)字:
new_year_2023 = datetime(2022, 12, 31)
datetime.timestamp(new_year_2023)
Output:
1672441200.0
1672441200 就是從 Unix 紀(jì)元開(kāi)始到 2022 年 12 月 31 日之間的秒數(shù)。
我們可以使用 fromtimestamp() 函數(shù)執(zhí)行逆運(yùn)算:
datetime.fromtimestamp(1672441200)
Output:
datetime.datetime(2022, 12, 31, 0, 0)
帶日期的算術(shù)運(yùn)算
有時(shí)我們可能想要計(jì)算兩個(gè)日期之間的差異或?qū)θ掌诤蜁r(shí)間執(zhí)行其他算術(shù)運(yùn)算。幸運(yùn)的是,Python 的工具包中有許多工具可以執(zhí)行此類計(jì)算。
基本算術(shù)運(yùn)算
我們可以執(zhí)行的第一個(gè)操作是計(jì)算兩個(gè)日期之間的差異。為此,我們使用減號(hào):
# Instatiate two dates
first_date = date(2022, 1, 1)
second_date = date(2022, 12, 31)
# Difference between two dates
date_diff = second_date - first_date
# Function to convert datetime to string
def dt_string(date, date_format="%B %d, %Y"):
return date.strftime(date_format)
print(f"The number of days and hours between {dt_string(first_date)} and {dt_string(second_date)} is {date_diff}.")
Output:
The number of days and hours between January 01, 2022 and December 31, 2022 is 364 days, 0:00:00
讓我們看看 first_date - second_date 返回什么類型的對(duì)象:
type(date_diff)
Output:
datetime.timedelta
此對(duì)象的類型是 datetime.timedelta,它的名稱中有 delta,指的是一個(gè)綠色字母 delta,在科學(xué)和工程中,描述了一種變化<實(shí)際上,這里它代表了時(shí)間上的變化(差異)。
如果我們只對(duì)兩個(gè)日期之間的天數(shù)感興趣怎么辦?我們可以訪問(wèn) timedelta 對(duì)象的不同屬性,其中之一稱為 .days。
print(f"The number of days between {dt_string(first_date)} and {dt_string(second_date)} is {(date_diff).days}.")Output:
The number of days between January 01, 2022 and December 31, 2022 is 364.
timedelta() 時(shí)間增量
現(xiàn)在我們知道了 timedelta 對(duì)象,是時(shí)候介紹 timedelta() 函數(shù)了。它允許我們通過(guò)加減時(shí)間單位(如天、年、周、秒等)對(duì)時(shí)間對(duì)象執(zhí)行許多算術(shù)運(yùn)算。例如,我們可能想知道從現(xiàn)在起 30 天后是一周中的哪一天。為此,我們必須創(chuàng)建一個(gè)表示當(dāng)前時(shí)間的對(duì)象和一個(gè)定義我們添加到其中的時(shí)間量的 timedelta 對(duì)象:
# Import timedelta
from datetime import timedelta
# Current time
now = datetime.now()
# timedelta of 30 days
one_month = timedelta(days=30)
# Day in one month/using dt_string function defined above
print(f"The day in 30 days is {dt_string(now + one_month)}.")
Output:
The day in 30 days is March 16, 2022.
如果我們查看 timedelta 函數(shù)的幫助頁(yè)面 (help(timedelta)),我們會(huì)看到它有以下參數(shù):days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours= 0,周=0。因此我們還可以練習(xí)在日期中添加或減去其他時(shí)間單位。例如,我們可以計(jì)算 2030 年新年前 12 小時(shí)的時(shí)間:
# New year 2030
new_year_2030 = datetime(2030, 1, 1, 0, 0)
# timedelta of 12 hours
twelve_hours = timedelta(hours=12)
# Time string of 12 hours before New Year 2023
twelve_hours_before = (new_year_2030 - twelve_hours).strftime("%B %d, %Y, %H:%M:%S")
# Print the time 12 hours before New Year 2023
print(f"The time twelve hours before New Year 2030 will be {twelve_hours_before}.")
Output:
The time twelve hours before New Year 2030 http://m.fisionsoft.com.cn/article/djgssoe.html


咨詢
建站咨詢
