Pythonで日付操作のエラーを安全に処理する方法(try / except 入門)
生徒
「日付を扱うときにエラーが出たら、どうしたらいいですか?プログラムが止まるのが怖いです。」
先生
「日付のエラーはよくある問題です。Pythonでは try と except を使って安全に処理できます。例え話で言うと、日付は電車の切符で、間違った切符を渡されたときに駅員(except)が対応してくれるイメージです。」
生徒
「具体的な使い方を教えてください!」
先生
「では、基本から順に、初心者にもわかるように説明します。」
1. なぜ日付でエラーが起きるのか?
日付のエラーは主に「形式が違う」「値が論理的におかしい」「外部入力が不正」の三つが原因です。たとえば「2023-02-30」のように存在しない日や、「2023/13/01」のように月の範囲を超えた値、あるいはユーザーが自由に入力した文字列などです。これらは ValueError やパースの失敗として発生します。
2. try / except の基本:安全に例外を受け止める
try ブロック内に「失敗するかもしれない処理」を書き、失敗したときに except で代替処理を行います。用語の補足:例外(Exception)はエラーのこと、パース(parse)は文字列を日付に変換することです。
from datetime import datetime
date_str = "2023-02-30" # 存在しない日
try:
dt = datetime.strptime(date_str, "%Y-%m-%d")
print("変換成功:", dt)
except ValueError as e:
print("日付の形式が正しくありません:", e)
(ここに出力結果)
この例では ValueError を捕まえて、プログラムが止まらないようにしています。
3. 複数の例外を分けて処理する
日付操作では異なる例外を分けて処理することが大切です。たとえばパース失敗とネットワークエラーは別の対処が必要です。
from datetime import datetime
def parse_date(s):
try:
return datetime.strptime(s, "%Y-%m-%d")
except ValueError:
# フォーマットが違う場合、別のフォーマットを試す
try:
return datetime.strptime(s, "%Y/%m/%d")
except ValueError:
# どちらもダメなら None を返す(呼び出し元で扱いやすいように)
return None
print(parse_date("2023/12/01"))
print(parse_date("invalid-date"))
4. 入力検証で早めに弾く(防御的プログラミング)
例外は発生してから対処しますが、事前に入力が妥当かチェックすることも重要です。正規表現や簡単な文字列チェックで不正な入力を早期に弾けます。用語:正規表現(Regex)は文字列のパターンを表す方法です。
import re
from datetime import datetime
pattern = re.compile(r'^\d{4}-\d{2}-\d{2}$')
def safe_parse(s):
if not pattern.match(s):
return None
try:
return datetime.strptime(s, "%Y-%m-%d")
except ValueError:
return None
print(safe_parse("2023-12-01"))
print(safe_parse("12/01/2023"))
5. ログ出力とユーザーへのやさしいメッセージ
エラーを無視してはいけません。開発者向けにはログを残し、利用者向けには分かりやすいメッセージを返しましょう。ログは後で問題を追跡するために役立ちます。
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
date_str = "2023-02-30"
try:
dt = datetime.strptime(date_str, "%Y-%m-%d")
except ValueError as e:
logging.error("日付パース失敗: %s", e)
print("入力された日付が正しくありません。YYYY-MM-DD形式で再入力してください。")
6. 実践テクニック:デフォルト値、再試行、フォールバック
日付が取れないときはデフォルト値を使う、別の入力方法を促す、あるいはユーザーに再入力を求める、といった設計を考えます。自動で今日の日付に置き換える場合は注意深く判断してください。
from datetime import datetime
def parse_or_today(s):
try:
return datetime.strptime(s, "%Y-%m-%d")
except ValueError:
# フォールバックとして今日を返す(仕様で許される場合)
return datetime.today()
print(parse_or_today("invalid"))
7. 国際化とタイムゾーンに注意する
日付・時刻はタイムゾーンやロケール(地域設定)により意味が変わります。UTCやISO 8601(例: 2023-12-01T15:30:00Z)を使うと安全です。タイムゾーンを扱う場合は標準ライブラリの zoneinfo(Python3.9+)や外部ライブラリを検討します。タイムゾーン扱いのミスも例外を生みます。
8. まとめに代わる注意点(最後のチェックリスト)
- ユーザー入力は必ず検証する(正規表現や簡単な形式チェック)。
try / exceptで具体的な例外を捕まえる(except Exceptionの乱用は避ける)。- ログを残し、ユーザーにはわかりやすいエラーメッセージを返す。
- フォーマットのバリエーションを想定してフォールバックを用意する。
- タイムゾーンや国際化の要件を最初に確認する。
サンプル:ユーザー入力を安全に扱う簡単なフォーム処理例
from datetime import datetime
def handle_input(date_input):
# 予備チェック
if not date_input or len(date_input) < 8:
return "日付が短すぎます。YYYY-MM-DD形式で入力してください。"
# 変換試行
try:
dt = datetime.strptime(date_input, "%Y-%m-%d")
return f"受け取りました: {dt.date()}"
except ValueError:
return "日付の形式が不正です。YYYY-MM-DD形式で入力してください。"
print(handle_input("2023-12-01"))
print(handle_input("2023-02-30"))