📅 Python 時間管理:datetime 與 calendar 常用方法詳解
一、概述
在 Python 中,日期和時間處理主要依賴兩個標準庫:
datetime:處理時間點、日期時間計算、時區轉換、格式化與解析。calendar:處理日歷相關操作,如判斷閏年、獲取某月天數、生成日歷矩陣。
這兩個模塊結合使用,可以解決絕大多數日期、時間和日歷場景。
-
星期索引(weekday):
- 0 表示星期一,6 表示星期日。
-
月份索引:
- 1 表示一月,12 表示十二月。
二、?? datetime 模塊
1. 常用函數與方法
| 類/函數 | 方法/屬性 | 作用 |
|---|---|---|
| date(year, month, day) | .today() |
獲取今天的日期(naive,無時區) |
.fromordinal(n) |
由公歷序號(自公元 1-01-01 起)生成日期 | |
.isoformat() |
轉換為 ISO 8601 字符串 | |
.weekday() |
返回周幾(0=周一,6=周日) | |
.isoweekday() |
返回周幾(1=周一,7=周日) | |
.isocalendar() |
返回 (ISO 年, ISO 周, ISO 周內日) |
|
.replace(...) |
替換部分字段生成新對象 | |
| time(hour, minute, second, …) | .isoformat() |
ISO 8601 格式時間 |
.replace(...) |
替換時間字段 | |
| datetime(year, month, day, hour=0, …) | .now([tz]) |
當前本地時間,若傳 tz -> aware |
.utcnow() |
當前 UTC 時間(naive,??不含 tzinfo) | |
.fromtimestamp(ts, tz=None) |
時間戳轉 datetime | |
.utcfromtimestamp(ts) |
時間戳轉 naive UTC | |
.astimezone(tz) |
轉換為指定時區 | |
.timestamp() |
轉換為時間戳(float 秒) | |
.strftime(fmt) |
按格式輸出字符串 | |
.strptime(str, fmt) |
從字符串解析 datetime | |
.isoformat() / .fromisoformat() |
ISO 8601 格式互轉 | |
.date() |
取日期部分 | |
.time() |
取時間部分 | |
.replace(...) |
替換字段 | |
| timedelta(days=0, seconds=0, …) | .total_seconds() |
轉換為總秒數 |
| timezone(offset, name=None) | .utc |
UTC 時區常量 |
| 輔助 | .combine(date, time) |
合成 datetime |
.min / .max |
最小/最大日期時間 |
2. 示例
2.1 獲取當前日期/時間
from datetime import date, datetime, timezone
from zoneinfo import ZoneInfo
today = date.today()
print(today) # 今天日期 2025-08-31
now_local = datetime.now()
print(now_local) # 本地當前時間(naive) 2025-08-31 11:02:41.099034
now_utc = datetime.now(timezone.utc)
print(now_utc)# UTC 當前時間(aware) 2025-08-31 03:02:41.099034+00:00
now_tokyo = now_utc.astimezone(ZoneInfo("Asia/Tokyo")) # 轉東京時間
print(now_tokyo) # 2025-08-31 12:02:41.099034+09:00
now_sh = now_utc.astimezone(ZoneInfo("Asia/Shanghai")) # 轉上海時間
print(now_sh) # 2025-08-31 11:07:32.555357+08:00
2.2 時間戳互轉
from datetime import datetime, timezone
# 本地時間
ts = datetime.now()
print(ts) # 2025-08-31 11:18:38.005607
ts_timestamp = ts.timestamp() # datetime -> 時間戳(秒)
print(ts.timestamp()) # 1756610318.005607
dt = datetime.fromtimestamp(ts_timestamp ,tz=timezone.utc) # 時間戳 -> datetime(UTC)
print(dt) # 2025-08-31 03:18:38.005607+00:00
------------------------------------------------------------
# UTC時間
ts1 = datetime.now(timezone.utc)
print(ts1) # 2025-08-31 03:18:38.005607+00:00
ts1_timestamp = ts1.timestamp() # datetime -> 時間戳(秒)
print(ts1.timestamp()) # 1756610318.005607
dt1 = datetime.fromtimestamp(ts1_timestamp ,tz=timezone.utc) # 時間戳 -> datetime(UTC)
print(dt1) # 2025-08-31 03:18:38.005607+00:00
----
# datetime.timestamp() 永遠返回“自 1970-01-01 00:00:00 UTC 以來的秒數”,也就是說,不管你手里的 datetime 對象是哪個時區,它都會被先轉換成 UTC,然后再計算 Unix 時間戳。
2.3 日期加減 / 計算時間差
from datetime import datetime, timedelta
dt = datetime(2025, 8, 30, 9, 0)
print(dt,type(dt)) #2025-08-30 09:00:00 <class 'datetime.datetime'>
dt_plus = dt + timedelta(days=7) # 加一周
print(dt_plus,type(dt_plus)) # 2025-09-06 09:00:00 <class 'datetime.datetime'>
delta = dt_plus - dt
print(delta,type(delta)) # 7 days, 0:00:00 <class 'datetime.timedelta'>
print(delta.days) #時間差天數 7
print(delta.total_seconds()) # 時間差秒數 604800.0
2.4 獲取星期幾 / ISO 周
from datetime import date
d = date(2025, 8, 30)
print(d.weekday()) # 5 -> 周六 (0=周一)
print(d.isocalendar()) # (2025, 35, 6) -> ISO 年/周/周內日
2.5 本周一/周日
from datetime import datetime, timedelta
dt = datetime(2025, 8, 30)
monday = dt - timedelta(days=dt.weekday()) # 本周一
sunday = monday + timedelta(days=6) # 本周日
2.6 本月第一天/最后一天
from datetime import datetime
import calendar
dt = datetime(2025, 8, 30)
first_day = dt.replace(day=1) # 月初
last_day = dt.replace(day=calendar.monthrange(dt.year, dt.month)[1]) # 月末
2.7 求某月第 N 個星期 X
import calendar
from datetime import date
def nth_weekday(year, month, weekday, n):
weeks = calendar.monthcalendar(year, month)
count = 0
for w in weeks:
if w[weekday] != 0:
count += 1
if count == n:
return date(year, month, w[weekday])
print(nth_weekday(2025, 8, calendar.WEDNESDAY, 2)) # 2025-08-13
2.8 格式化與解析
from datetime import datetime
dt = datetime(2025, 8, 30, 9, 5, 6)
s = dt.strftime("%Y-%m-%d %H:%M:%S") # 格式化
dt2 = datetime.strptime(s, "%Y-%m-%d %H:%M:%S") # 解析
2.9 ISO 格式互轉(推薦)
from datetime import datetime
dt = datetime(2025, 8, 30, 9, 5, 6)
s = dt.isoformat() # '2025-08-30T09:05:06'
dt2 = datetime.fromisoformat(s) # 解析回來
三、?? calendar 模塊
1、常用函數與方法
| 函數/類 | 方法/屬性 | 作用 |
|---|---|---|
| 基礎函數 | isleap(year) |
判斷是否閏年 |
leapdays(y1, y2) |
統計區間 [y1, y2) 內閏年數 |
|
weekday(y,m,d) |
返回星期幾(0=周一,6=周日) | |
monthrange(y,m) |
返回 (當月第一天星期幾, 當月天數) |
|
monthcalendar(y,m) |
返回“月歷矩陣”,每周 7 天,不在本月的日子為 0 | |
weekheader(n) |
返回一行周標題(寬度 n,例如 "Mo Tu We") |
|
| 文本日歷 | TextCalendar(firstweekday=0) |
文本日歷對象(0=周一) |
.formatmonth(y,m) |
返回字符串形式的月歷 | |
.prmonth(y,m) |
打印月歷到終端 | |
.prcal(y) |
打印整年日歷 | |
| HTML 日歷 | HTMLCalendar(firstweekday=0) |
HTML 日歷對象 |
.formatmonth(y,m) |
生成 HTML 表格月歷 | |
.formatyear(y) |
生成 HTML 表格全年日歷 | |
| 本地化日歷 | LocaleTextCalendar/LocaleHTMLCalendar |
按 locale 輸出月名、周名 |
| 常量 | calendar.MONDAY ... SUNDAY |
星期常量 0–6 |
calendar.month_name[1..12] |
月份全名 | |
calendar.month_abbr[1..12] |
月份縮寫 | |
calendar.day_name[0..6] |
星期全名 | |
calendar.day_abbr[0..6] |
星期縮寫 | |
| 設置 | setfirstweekday(n) |
設置周起始(0=周一,6=周日) |
firstweekday() |
返回當前周起始設置 |
2. 示例
2.1 基礎示例
import calendar
# 閏年判斷
print(calendar.isleap(2024)) # True
# 本月信息
print(calendar.monthrange(2025, 8)) # (4, 31) -> 周五開始,共 31 天
# 月歷矩陣
print(calendar.monthcalendar(2025, 8))
# 打印月歷
calendar.prmonth(2025, 8)
# HTML 月歷
hc = calendar.HTMLCalendar()
print(hc.formatmonth(2025, 8))
2.2 日歷相關(calendar)
import calendar
print(calendar.isleap(2024)) # 閏年? True
print(calendar.monthrange(2025, 8)) # (4, 31) -> 月首是周五, 31天
print(calendar.weekday(2025, 8, 30)) # 5 -> 周六
print(calendar.monthcalendar(2025, 8)) # 返回矩陣 [[0,0,0,1,2,...], ...]
calendar.prmonth(2025, 8) # 打印月歷
calendar.prcal(2025) # 打印整年月歷
2.3 HTML 日歷(網頁場景)
import calendar
hc = calendar.HTMLCalendar(firstweekday=calendar.SUNDAY)
html = hc.formatmonth(2025, 8)
print(html) # HTML 表格,可直接放到網頁
2.4 常用函數詳解(配示例)
1?? calendar.month(year, month)
作用:返回一個多行字符串形式的指定月份日歷。
import calendar
print(calendar.month(2025, 8))
?? 輸出:
August 2025
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
2?? calendar.calendar(year, w=2, l=1, c=6)
作用:返回一個多行字符串形式的全年日歷。
w: 每個日期的寬度l: 每一周之間的行數c: 每個月之間的間距
print(calendar.calendar(2025))
3?? calendar.isleap(year)
作用:判斷某一年是否為閏年。返回布爾值。
calendar.isleap(2024) # True
calendar.isleap(2025) # False
4?? calendar.leapdays(y1, y2)
作用:返回在區間 [y1, y2) 中閏年的數量。
calendar.leapdays(2000, 2025) # 6
?? 注意:不包括 y2 本身
5?? calendar.weekday(year, month, day)
作用:返回指定日期的星期幾,0 表示星期一。
calendar.weekday(2025, 8, 4) # 0 (星期一)
6?? calendar.monthrange(year, month)
作用:返回一個元組 (start_day, total_days):
start_day是該月 1 號是星期幾(0=周一)total_days是該月的天數
calendar.monthrange(2025, 8) # (4, 31)
7?? calendar.monthcalendar(year, month)
作用:返回該月的日歷,格式為二維列表。每一子列表代表一周,0 表示該位置無效(即不屬于該月的日期)。
calendar.monthcalendar(2025, 8)
?? 輸出樣例:
[
[0, 0, 0, 0, 1, 2, 3],
[4, 5, 6, 7, 8, 9,10],
[11,12,13,14,15,16,17],
...
]
8?? calendar.setfirstweekday(n)
作用:設置每周的起始星期日。默認是 0(星期一)。
calendar.setfirstweekday(6) # 以周日為第一天
print(calendar.month(2025, 8))
9?? calendar.day_name 和 calendar.day_abbr
作用:獲取星期名稱(英文全稱和簡稱),支持索引訪問。
list(calendar.day_name) # ['Monday', 'Tuesday', ..., 'Sunday']
calendar.day_name[0] # 'Monday'
calendar.day_abbr[0] # 'Mon'
?? calendar.month_name 和 calendar.month_abbr
作用:獲取月份英文名(全稱/簡稱),索引 1-12 表示月份。
list(calendar.month_name) # ['', 'January', ..., 'December']
calendar.month_name[8] # 'August'
calendar.month_abbr[8] # 'Aug'
?? 注意:索引 0 是空字符串。
四、場景示例
1. 每月第一個星期一
# 基礎版
import pandas as pd
from datetime import datetime, timedelta
import calendar
def get_first_monday_of_month(year, month):
first_day = datetime(year, month, 1)
if first_day.weekday() == 0:
return first_day
else:
days_to_add = (0 - first_day.weekday()) % 7
return first_day + timedelta(days=days_to_add)
# def get_first_monday(year, month):
# # 獲取該月第一天是星期幾(0=Monday, 6=Sunday)
# first_day_weekday = calendar.weekday(year, month, 1)
# # 計算需要加幾天才能到下一個星期一
# days_to_add = (0 - first_day_weekday) % 7
# return datetime(year, month, 1) + timedelta(days=days_to_add)
# 當前時間
now = datetime.now()
start_year = now.year
start_month = now.month
restart_times = []
for i in range(12):
year = start_year + (start_month + i - 1) // 12
month = (start_month + i - 1) % 12 + 1
first_monday = get_first_monday_of_month(year, month)
restart_time = first_monday.replace(hour=6, minute=31, second=0, microsecond=0)
restart_times.append(restart_time.strftime("%Y-%m-%d %H:%M"))
# 創建 DataFrame
df = pd.DataFrame(restart_times, columns=["Restart Time"])
# 導出到 Excel
output_file = "Windows-Restarted.xlsx"
df.to_excel(output_file, index=False)
print(f"Excel 文件已生成:{output_file}")
2. 每天凌晨一點
1. 從當前時間開始
from datetime import datetime,timedelta
from openpyxl import load_workbook
import calendar
def get_time(year,month,day):
dt=datetime(year,month,day)
return datetime.strftime((dt + timedelta(hours=1)),'%Y%m%d%H%M%S')
start_year=datetime.now().year
start_month=datetime.now().month
start_day=datetime.now().day
dt=[]
for i in range(12):
year = start_year + (start_month + i - 1) // 12
month = (start_month + i - 1) % 12 + 1
# 獲取該月的實際天數
_, num_days = calendar.monthrange(year, month)
for j in range(num_days):
day = j + 1 # 生成從1到num_days的天數
time = get_time(year, month, day)
dt.append(time)
data_str = ",".join(dt)
# #
# print(data_str)
# 已有文件
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1,319):
if ws[f'k{i}'].value == "凌晨1點(test)":
ws[f'L{i}'] = data_str
wb.save('time.xlsx')
print('done')
--------------------------------------------------------------------------------------------
2. 從指定時間開始,每天凌晨一點
from datetime import datetime,timedelta
from openpyxl import load_workbook
import calendar
def get_time(year,month,day):
dt=datetime(year,month,day)
return datetime.strftime((dt + timedelta(hours=1)),'%Y%m%d%H%M%S')
start_year=datetime.now().year
start_month=6
start_day=1
dt=[]
for i in range(3):
year = start_year + (start_month + i - 1) // 12
month = (start_month + i - 1) % 12 + 1
# 獲取該月的實際天數
_, num_days = calendar.monthrange(year, month)
for j in range(num_days):
day = j + 1 # 生成從1到num_days的天數
time = get_time(year, month, day)
dt.append(time)
data_str = ",".join(dt)
# #
# print(data_str)
# 已有文件
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1,319):
if ws[f'k{i}'].value == "凌晨1點":
ws[f'L{i}'] = data_str
wb.save('time.xlsx')
print('done')
3. 每月第二個周三晚8點
# 指定時間開始,指定時間結束
from datetime import datetime,timedelta
from openpyxl import load_workbook
def get_time(year,month):
dt=datetime(year,month,1)
if dt.weekday() == 2:
return datetime.strftime(dt + timedelta(days=7,hours=20),'%Y%m%d%H%M%S')
else:
return datetime.strftime((dt + timedelta(days=((2-dt.weekday())%7+7),hours=20)),'%Y%m%d%H%M%S')
start_year=datetime.now().year
start_month=6
dt=[]
for i in range(3):
year = start_year + (start_month + i-1 ) // 12
month = (start_month + i-1) %12 +1
time = get_time(year,month)
dt.append(time)
data_str = ",".join(dt)
# 寫入到Excel
# 文件不存在
# wb = Workbook()
# ws = wb.active
# ws['A1'] = data_str
# wb.save('output.xlsx')
# 已有文件
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1,319):
if ws[f'k{i}'].value == "第二個周三晚8點":
ws[f'L{i}'] = data_str
wb.save('time.xlsx')
print('done')
4. 每季度第一周三國內晚7點
# 指定時間開始,指定時間結束
from datetime import datetime,timedelta
from openpyxl import load_workbook
import calendar
def get_time(year,month):
dt=datetime(year,month,1)
if dt.weekday() == 2:
return datetime.strftime(dt + timedelta(hours=19),'%Y%m%d%H%M%S')
else:
return datetime.strftime((dt + timedelta(days=((2-dt.weekday())%7),hours=19)),'%Y%m%d%H%M%S')
dt=[]
for y in [2025,2026,2027]:
for m in [1,4,7,10]:
time = get_time(y, m)
dt.append(time)
data_str = ",".join(dt)
# #
print(data_str)
#
# 已有文件
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1,319):
if ws[f'k{i}'].value == "第一周三國內晚7-10點" or ws[f'k{i}'].value == "第一周三國內晚7-10點(owner手動重啟)":
ws[f'L{i}'] = data_str
wb.save('time.xlsx')
print('done')
5. 每月1號1點
# 指定時間,從幾月開始,到幾月結束,幾號,幾點
from datetime import datetime,timedelta
from openpyxl import load_workbook
import calendar
def get_time(year,month):
dt=datetime(year,month,1)
return datetime.strftime((dt + timedelta(hours=1)),'%Y%m%d%H%M%S')
start_year=datetime.now().year
start_month=6
dt=[]
for i in range(3):
year = start_year + (start_month + i - 1) // 12
month = (start_month + i - 1) % 12 + 1
time = get_time(year, month)
dt.append(time)
data_str = ",".join(dt)
# print(data_str)
# 已有文件
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1,319):
if ws[f'k{i}'].value == "每月1號1點":
ws[f'L{i}'] = data_str
wb.save('time.xlsx')
print('done')
6. 每月的每周x的y點
from datetime import datetime, timedelta
import calendar
from openpyxl import load_workbook
def get_monthly_mondays(year, month):
first_day = datetime(year, month, 1)
last_day = datetime(year, month, calendar.monthrange(year, month)[1])
mondays = []
current_day = first_day
while current_day <= last_day:
if current_day.weekday() == 0: # 0表示星期一
monday = current_day.replace(hour=2)
mondays.append(monday.strftime('%Y%m%d%H%M%S'))
current_day += timedelta(days=1)
return mondays
def main():
current_year = datetime.now().year
current_month = 6
dates = []
for i in range(3):
year = current_year + (current_month + i - 1) // 12
month = (current_month + i - 1) % 12 + 1
mondays = get_monthly_mondays(year, month)
dates.extend(mondays)
data_str = ",".join(dates)
return data_str
if __name__ == "__main__":
wb = load_workbook('time.xlsx')
ws = wb['Sheet1']
for i in range(1, 319):
if ws[f'k{i}'].value == "每周一2點":
ws[f'L{i}'] = main()
wb.save('time.xlsx')
print('done')
7. 每月最后一個周x
from datetime import datetime, timedelta
import calendar
from openpyxl import load_workbook
def get_monthly_mondays(year, month):
# 獲取該月的最后一天
_, last_day_of_month = calendar.monthrange(year, month)
# 構造該月最后一天的日期對象
last_day = datetime(year, month, last_day_of_month)
if last_day.weekday() == 6:
return datetime.strftime(last_day+timedelta(hours=4),'%Y%m%d%H%M%S')
else:
return datetime.strftime(last_day-timedelta(days=(last_day.weekday()-6)%7) +timedelta(hours=4),'%Y%m%d%H%M%S')
def main():
current_year = datetime.now().year
current_month = 6
dates = []
for i in range(3):
year = current_year + (current_month + i - 1) // 12
month = (current_month + i - 1) % 12 + 1
mondays = get_monthly_mondays(year, month)
dates.append(mondays)
data_str = ",".join(dates)
return data_str
if __name__ == "__main__":
wb = load_workbook('1Windows-Restarted.xlsx')
ws = wb['Sheet1']
for i in range(1, 319):
if ws[f'k{i}'].value == "time.xlsx":
ws[f'L{i}'] = main()
wb.save('time.xlsx')
print('done')

浙公網安備 33010602011771號