【小練習】用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
工程師的詩意午後
10會員
34內容數
在這裡,我讓程式碼與詩意共存, 生活不只有規則與邏輯,也有感受與想像, 有時是寫程式時的靈感,有時是半夜裡的一首詩, 願這些文字,帶給你一點溫度。
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樣超實用旅遊好物!減緩我的焦慮感。
Thumbnail
去歐洲真的是又興奮又緊張。網路上常說歐洲治安不好,行前說明會時領隊也提醒:「不要背後背包,隨身物要放在前面比較安全!」 但出國玩總是想打扮得美美的啊~而且隨身總得帶些實用小物:雨傘、濕紙巾、小瓶水、萬用藥膏……體積雖小,但零零總總裝起來也不少。我在蝦皮購買了這4樣超實用旅遊好物!減緩我的焦慮感。
Thumbnail
開箱 3 套深受 0-6 歲寶寶喜愛的互動式童書,包含 Bizzy Bear 推拉書、小小音樂大師有聲書、Poke A Dot 泡泡書,有效提升寶寶閱讀興趣與親子共讀時光。搭配蝦皮雙 11 購物攻略,教你如何鎖定免運、折價券、高額回饋,並透過蝦皮分潤計畫,將日常購物開銷轉化為穩定育兒基金,聰明消費。
Thumbnail
開箱 3 套深受 0-6 歲寶寶喜愛的互動式童書,包含 Bizzy Bear 推拉書、小小音樂大師有聲書、Poke A Dot 泡泡書,有效提升寶寶閱讀興趣與親子共讀時光。搭配蝦皮雙 11 購物攻略,教你如何鎖定免運、折價券、高額回饋,並透過蝦皮分潤計畫,將日常購物開銷轉化為穩定育兒基金,聰明消費。
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
一月-一元初始萬象新,轉輪新情心態空 二月-踏步更動心不動,穩步踏行無旁物 三月-能量起伏考人心,從心調整眼觀心 四月-世界新界舊換新,開闊心情不糾結 五月-嘗試體驗新事物,學習積累終不悔 六月-年中已到反思心,萬事變化皆因緣 七月--平順源於心平靜,環境萬變堅己路 八月
Thumbnail
跨年,是什麼概念呢?一個計時週期的結束,下一個週期的開始,僅此而已?那,就讓時間這樣過去吧,閉上眼睛,再張開後又是一個循環的開始。
Thumbnail
跨年,是什麼概念呢?一個計時週期的結束,下一個週期的開始,僅此而已?那,就讓時間這樣過去吧,閉上眼睛,再張開後又是一個循環的開始。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News