想不想用 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
這段做的事是:
- 如果這個月是 12 月,下一個月就是隔年 1 月。
- 否則就直接用當年的下個月。
- 然後從「下個月的第一天」減掉 1 天,就可以知道「這個月的最後一天」。
- 用
.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 月為例)



重點教學說明
datetime.date(year, month, 1)
建立日期物件
weekday()
回傳 0=週一 ~ 6=週日(我們轉為 0=週日)
timedelta(days=1)
幫助找出當月最後一天
{:>3}
對齊輸出,讓日期排得整齊