iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Modern Web

每天一點 API:打造我的生活小工具系列 第 12

Day 12 — 日曆 API:API 失敗也能顯示正確星期

  • 分享至 

  • xImage
  •  

今天是星期幾?

這個問題看起來很簡單,但其實背後牽涉到時間處理、時區判斷,還有 API 的應用。

今天我就要來練習日曆與時間 API,學習如何在 Python 程式裡正確取得「今天是星期幾」。

為什麼要學時間 API?

  1. 時間是大部分系統都會用到的重要資訊
    幾乎所有軟體系統都會處理時間,例如活動時間、報表日期、訂單時間等。

  2. 本地的時間不一定等於伺服器的時間
    不同地區會有不同的時區,時鐘也可能不同步,所以要注意時間的準確性。

  3. 很多 API 會提供統一的標準時間
    通常是用 UTC(世界協調時間)或指定某個時區,讓使用上更統一和可靠。

本機時間的處理方式

  1. 使用 Python 的 datetime 模組搭配 zoneinfo 模組
  • datetime 用來取得日期和時間

  • zoneinfo 用來處理時區問題

  1. 取得今天日期與星期幾
  • 使用 datetime.now() 取得現在的本機時間

  • .date() 取出日期

  • .weekday().isoweekday() 取得星期幾

  1. 把星期數字轉成中文星期(星期一~星期日)

範例程式碼

from datetime import datetime 

從標準庫引入 datetime 類別,等一下用它取得現在時間與格式化日期。

try:
    from zoneinfo import ZoneInfo   # Python 3.9+
except ImportError:
    # 若舊版 Python,先: pip install backports.zoneinfo
    from backports.zoneinfo import ZoneInfo

嘗試匯入內建的 ZoneInfo(用來處理時區)。

WEEK_ZH = ["星期一","星期二","星期三","星期四","星期五","星期六","星期日"]

準備一個星期對照表。

def today_weekday_zh(tz: str = "Asia/Taipei") -> str:

定義一個函式,參數tz是時區,預設用 Asia/Taipei;回傳一段中文字串。

    now = datetime.now(ZoneInfo(tz))

取得指定時區的「現在時間」。
ZoneInfo(tz) 會把 "Asia/Taipei" 轉成正確的時區資訊。

    return now.strftime("%Y-%m-%d") + "(" + WEEK_ZH[now.weekday()] + ")"

把日期格式化成 YYYY-MM-DD,再接上中文星期。
now.weekday() 會回 0~6,拿來當 WEEK_ZH 的索引。

if __name__ == "__main__":
    print("今天是:", today_weekday_zh())
  • 小提醒:在執行程式碼前,要先確認環境裡安裝tzdata。(因為 Windows 沒內建 IANA tz DB,zoneinfo需要tzdata套件補上)
pip install tzdata

執行結果:

今天是: 2025-09-24(星期三)

API + 退回本機時間

  • 優先使用網路上的時間 API,取得標準時間,確保時間準確與跨時區支援。

  • 如果 API 呼叫失敗,例如網路問題,就自動退回使用電腦本機時間,讓程式依然能運作。

  • 加入參數選項,讓使用者可以指定時區,也可以指定時間來源(API 或本機)。

程式範例說明

import argparse
from datetime import datetime # 處理日期時間
try:
    from zoneinfo import ZoneInfo # 用 IANA 時區字串(像 "Asia/Taipei")取得正確時區。
except ImportError:
    from backports.zoneinfo import ZoneInfo
import requests # 發 HTTP 請求去叫 API。

主要用 argparse 來解析程式執行時的參數。
用 zoneinfo 取得指定時區的本地時間。
用 requests 呼叫世界時間 API 取得時間。

WEEK_ZH = ["星期一","星期二","星期三","星期四","星期五","星期六","星期日"]

準備中文星期對照表。

def local_today(tz: str) -> str:
    now = datetime.now(ZoneInfo(tz))
    return now.strftime("%Y-%m-%d") + "(" + WEEK_ZH[now.weekday()] + ")"

這部分是本機時間版本。

API版本

def api_today(tz: str, timeout: float = 10.0) -> str:
    url = f"https://worldtimeapi.org/api/timezone/{tz}"
    r = requests.get(url, timeout=timeout)
    r.raise_for_status()
    iso = (r.json()["datetime"] or "").replace("Z", "+00:00")
    dt = datetime.fromisoformat(iso)  # 解析 API 時間
    return dt.strftime("%Y-%m-%d") + "(" + WEEK_ZH[dt.weekday()] + ")"

參數與流程

def main():
    ap = argparse.ArgumentParser(description="顯示今天是星期幾")
    ap.add_argument("--tz", default="Asia/Taipei", help="時區(預設:Asia/Taipei)")
    ap.add_argument("--source", choices=["auto","api","local"], default="auto",
                    help="時間來源:auto=API優先, 失敗退本機;api=只用API;local=只用本機")
    args = ap.parse_args()
    if args.source == "local":
        print(local_today(args.tz))
        return

只用本機:直接印出本機計算結果。

    if args.source == "api":
        try:
            print(api_today(args.tz))
            return
        except requests.exceptions.RequestException as e:
            print("API 失敗:", e)
            return

只用 API:成功就印結果;如果有任何網路或是HTTP 錯誤,就印「API 失敗」並結束

# auto 模式
    try:
        print(api_today(args.tz))
    except requests.exceptions.RequestException:
        print("API 失敗,改用本機時間…")
        print(local_today(args.tz))

auto:先試 API;如果失敗(逾時、連線、HTTP 錯等都屬於 RequestException),自動退回本機,程式不會中斷。

if __name__ == "__main__":
    main()

執行結果:

API 失敗,改用本機時間…
2025-09-24(星期三)

這裡雖然留了完整的 API + 失敗退回本機版本程式碼,代表今天的練習還是圍繞在 API 使用上,

但是我要在這裡說明,因為目前公開時間 API 經常不穩定,

我實際執行時經常碰到 API 呼叫失敗或連線問題,導致程式自動改用本機時間。

但也正是因為如此,正好示範了錯誤處理的重要,說明在實務中,當依賴的外部服務不穩定時,

需要設計備援機制(Fallback)來確保核心功能不中斷。

今日總結

  • 學會用本機時間搭配 datetime + zoneinfo 取得今天日期與星期幾。

  • 嘗試呼叫世界時間 API 取得標準時間,但發現 API 可能不穩定。

  • 理解到錯誤處理與 Fallback(退回本機時間)的必要性。

  • 實際體會:API 再好,也要有備援機制,才能讓程式穩定運作。


上一篇
Day 11 — JSON vs XML:API 為什麼更愛 JSON
下一篇
Day13 — API 資料怎麼存?CSV、JSON、SQLite 練習
系列文
每天一點 API:打造我的生活小工具13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言