【小練習】用Python打造萬年曆工具:內建 datetime 即可搞定

更新於 發佈於 閱讀時間約 12 分鐘

想不想用 Python 自己做出一個萬年曆工具?

這篇教你不使用任何額外套件,只靠 Python 內建的 datetime 模組,就能:

  • 🗓 自動判斷該月有幾天(含閏年)
  • 📅 推算該月第一天是星期幾
  • 🔢 輸出整齊排版的日曆表

功能簡介

使用者輸入:

  • 年份(例如:2025)
  • 月份(例如:6)

程式會:

  • 自動判斷該月總天數(28、29、30、31)
  • 計算該月第一天是星期幾(不用手動輸入)
  • 印出格式整齊的日曆表

1.引入模組與相容處理

# -*- coding: utf-8 -*-
from __future__ import print_function
import datetime
  • # -*- coding: utf-8 -*-:告訴 Python 這個檔案是用 UTF-8 編碼,這樣中文才不會出錯。
  • from __future__ import print_function:這讓你在 Python 2 裡面也可以使用 print("文字") 的寫法(像 Python 3)。
  • import datetime:匯入 Python 內建的 datetime 模組,幫我們處理日期與時間相關的事情(像幾月有幾天、某天是星期幾)。

2.計算該月的天數

def get_days_in_month(year, month):
if month == 12:
next_month = datetime.date(year + 1, 1, 1)
else:
next_month = datetime.date(year, month + 1, 1)
last_day = next_month - datetime.timedelta(days=1)
return last_day.day

這段做的事是:

  1. 如果這個月是 12 月,下一個月就是隔年 1 月。
  2. 否則就直接用當年的下個月。
  3. 然後從「下個月的第一天」減掉 1 天,就可以知道「這個月的最後一天」。
  4. .day 取得那天的「日期數字」,例如 31

➡️ 這方法可以自動判斷 2 月有 28 還是 29 天,也不用硬寫每個月的天數!


3.取得該月 1 號是星期幾

def get_start_weekday(year, month):
first_day = datetime.date(year, month, 1)
weekday = first_day.weekday() # 傳回 0=Monday ~ 6=Sunday
return (weekday + 1) % 7 # 轉成 0=Sunday ~ 6=Saturday

說明:

  • 建立一個「該月第 1 天」的日期物件。
  • weekday() 會回傳:星期一是 0、星期二是 1...星期日是 6。
  • 但我們想要 星期日是 0、星期一是 1...星期六是 6(這樣才符合日曆排版),所以我們加 1 再模 7。

4.印出日曆內容

def print_calendar(year, month):
days = get_days_in_month(year, month)
start_day = get_start_weekday(year, month)

print("📅 %d 年 %d 月日曆" % (year, month))
print("Sun Mon Tue Wed Thu Fri Sat")
  • 先取得這個月的天數與起始星期幾。
  • 印出標題與星期幾的欄位標頭,方便閱讀。

5.補空格對齊開頭

 for _ in range(start_day):
print(" ", end="")
  • 如果第一天不是星期日,我們要在前面補幾格空白,讓日期對齊正確位置。
  • 每格空白是 4 個字元寬,和日期欄寬一致。

6.一天一天列印出來

day = 1
current = start_day

while day <= days:
print("{:>3}".format(day), end=" ")
current += 1
if current == 7:
print("")
current = 0
day += 1

print("")

說明:

  • day = 1 是從 1 號開始印。
  • while day <= days 控制不要超出月底。
  • {:>3} 表示將數字靠右對齊,寬度是 3,確保排版整齊。
  • 每列印一個數字,就把 current(目前是星期幾)加 1。
  • 如果到了星期六(index 6 → 變成 7),就換行並重設為 0(日)。

7.主程式 main()

def main():
try:
try:
year = int(raw_input("請輸入年份(如 2025):"))
month = int(raw_input("請輸入月份(1~12):"))
except NameError:
year = int(input("請輸入年份(如 2025):"))
month = int(input("請輸入月份(1~12):"))

print("")
print_calendar(year, month)
except Exception as e:
print("輸入錯誤:", e)
  • 嘗試用 raw_input()(Python 2)或 input()(Python 3)讓使用者輸入年份與月份。
  • 輸入完成後,呼叫 print_calendar() 印出結果。
  • 有錯就會顯示「輸入錯誤」。

8.執行進入點

if __name__ == "__main__":
main()
  • 表示這支程式是被「直接執行」的話,就會執行 main() 函式。


🧑‍💻 完整程式碼

# -*- coding: utf-8 -*-
from __future__ import print_function
import datetime # 內建模組,用來處理日期

# 取得指定年月的「天數」
def get_days_in_month(year, month):
if month == 12:
# 如果是 12 月,下個月是明年 1 月
next_month = datetime.date(year + 1, 1, 1)
else:
# 否則就是當年下個月
next_month = datetime.date(year, month + 1, 1)

# 該月最後一天 = 下個月的第一天 - 1 天
last_day = next_month - datetime.timedelta(days=1)
return last_day.day

# 取得該月 1 號是星期幾(0=Sunday)
def get_start_weekday(year, month):
first_day = datetime.date(year, month, 1)
weekday = first_day.weekday() # 傳回 0=Monday ~ 6=Sunday
return (weekday + 1) % 7 # 我們轉換成 0=Sunday

# 印出排版整齊的日曆
def print_calendar(year, month):
days = get_days_in_month(year, month) # 取得天數
start_day = get_start_weekday(year, month) # 取得起始星期

print("📅 %d 年 %d 月日曆" % (year, month))
print("Sun Mon Tue Wed Thu Fri Sat") # 星期標題列

# 開頭空格填補對齊
for _ in range(start_day):
print(" ", end="")

day = 1
current = start_day

# 開始印日期
while day <= days:
print("{:>3}".format(day), end=" ") # 每個欄位寬度 3,靠右對齊
current += 1
if current == 7:
print("") # 如果到星期六,換行
current = 0
day += 1

print("") # 最後換行

# 主流程
def main():
try:
# 支援 Python 2 和 Python 3 的輸入方式
try:
year = int(raw_input("請輸入年份(如 2025):"))
month = int(raw_input("請輸入月份(1~12):"))
except NameError:
year = int(input("請輸入年份(如 2025):"))
month = int(input("請輸入月份(1~12):"))

print("")
print_calendar(year, month) # 呼叫主功能
except Exception as e:
print("輸入錯誤:", e)

# 執行主程式
if __name__ == "__main__":
main()


執行範例(以 2025 年 6 月為例)

raw-image
raw-image
raw-image


重點教學說明

datetime.date(year, month, 1)

建立日期物件

weekday()

回傳 0=週一 ~ 6=週日(我們轉為 0=週日)

timedelta(days=1)

幫助找出當月最後一天

{:>3}

對齊輸出,讓日期排得整齊









留言
avatar-img
留言分享你的想法!
avatar-img
工程師的詩意午後
5會員
26內容數
在這裡,我讓程式碼與詩意共存, 生活不只有規則與邏輯,也有感受與想像, 有時是寫程式時的靈感,有時是半夜裡的一首詩, 願這些文字,帶給你一點溫度。
2025/05/19
你是否曾想過,如何用程式讓「hello」變成「olleh」?今天,我們就從一個最簡單、卻也最實用的 Python 練習開始:反轉字串(Reverse a String)。 這個小小的任務,是 Python 新手很常遇到的練習題之一,不僅能幫助你熟悉字串(str)操作,也會讓你對 Python 的語
2025/05/19
你是否曾想過,如何用程式讓「hello」變成「olleh」?今天,我們就從一個最簡單、卻也最實用的 Python 練習開始:反轉字串(Reverse a String)。 這個小小的任務,是 Python 新手很常遇到的練習題之一,不僅能幫助你熟悉字串(str)操作,也會讓你對 Python 的語
2025/04/16
學習如何使用Python編寫一個數字猜謎遊戲,從中學習隨機數生成、使用者輸入、條件判斷和迴圈等程式設計基礎概念。
Thumbnail
2025/04/16
學習如何使用Python編寫一個數字猜謎遊戲,從中學習隨機數生成、使用者輸入、條件判斷和迴圈等程式設計基礎概念。
Thumbnail
2025/04/16
在學習 Python 的初期,我們常常會從一些小小的專案開始練習。今天要帶你做的,就是其中一個經典的入門練習——簡單計算機。 這個練習的目標是:讓程式接收兩個數字和一個運算符(+、-、*、/),並回傳正確的計算結果。 可以在Visual Studio Code中執行 #!/usr/bin/
Thumbnail
2025/04/16
在學習 Python 的初期,我們常常會從一些小小的專案開始練習。今天要帶你做的,就是其中一個經典的入門練習——簡單計算機。 這個練習的目標是:讓程式接收兩個數字和一個運算符(+、-、*、/),並回傳正確的計算結果。 可以在Visual Studio Code中執行 #!/usr/bin/
Thumbnail
看更多
你可能也想看
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
紀錄時間2024/07/30
Thumbnail
紀錄時間2024/07/30
Thumbnail
  接續上一篇文章,換言之,不會因為放假不能睡晚而影響到心情,就算六日都早起,週一也可以保持平靜的心情上班。而在新的一年裡,無論是以一月一日或農曆春節過後為起始日,先將計畫安排好,心裡也會有個底,知道這一年要完成什麼計畫。對於工作的內容,可以用兩個角度來思考:         第一,如果是
Thumbnail
  接續上一篇文章,換言之,不會因為放假不能睡晚而影響到心情,就算六日都早起,週一也可以保持平靜的心情上班。而在新的一年裡,無論是以一月一日或農曆春節過後為起始日,先將計畫安排好,心裡也會有個底,知道這一年要完成什麼計畫。對於工作的內容,可以用兩個角度來思考:         第一,如果是
Thumbnail
永遠不要預期貓的使用方法。
Thumbnail
永遠不要預期貓的使用方法。
Thumbnail
最近這一兩年,市面上突然多出很多行事曆工具可以選擇,不管是 Google calendar 的更新、Cron、Morgan、Rise、一直到最近出現的 HEY 跟 amie,在這麼多的行事曆中,其實只要掌握好核心概念,就可以掌握主動權,來提升生產力。
Thumbnail
最近這一兩年,市面上突然多出很多行事曆工具可以選擇,不管是 Google calendar 的更新、Cron、Morgan、Rise、一直到最近出現的 HEY 跟 amie,在這麼多的行事曆中,其實只要掌握好核心概念,就可以掌握主動權,來提升生產力。
Thumbnail
因為我們每天都會被問不只一次,乾脆把日期都整理出來,這樣大家查找更方便。 整年的新月|滿月| 八大節慶的日期都在上面囉。 因為是工作了10個小時後老眼昏花整理出來的,如果有誤植的話,再跟我們說,會立即修正喔。 預祝大家週末愉快。我們也要下班落跑啦~ ▍限量Imbolc蠟燭預購中:
Thumbnail
因為我們每天都會被問不只一次,乾脆把日期都整理出來,這樣大家查找更方便。 整年的新月|滿月| 八大節慶的日期都在上面囉。 因為是工作了10個小時後老眼昏花整理出來的,如果有誤植的話,再跟我們說,會立即修正喔。 預祝大家週末愉快。我們也要下班落跑啦~ ▍限量Imbolc蠟燭預購中:
Thumbnail
一月-一元初始萬象新,轉輪新情心態空 二月-踏步更動心不動,穩步踏行無旁物 三月-能量起伏考人心,從心調整眼觀心 四月-世界新界舊換新,開闊心情不糾結 五月-嘗試體驗新事物,學習積累終不悔 六月-年中已到反思心,萬事變化皆因緣 七月--平順源於心平靜,環境萬變堅己路 八月
Thumbnail
一月-一元初始萬象新,轉輪新情心態空 二月-踏步更動心不動,穩步踏行無旁物 三月-能量起伏考人心,從心調整眼觀心 四月-世界新界舊換新,開闊心情不糾結 五月-嘗試體驗新事物,學習積累終不悔 六月-年中已到反思心,萬事變化皆因緣 七月--平順源於心平靜,環境萬變堅己路 八月
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News