【Python完全ガイド】現在の年月日を取得する方法|初心者向け実用的解説

python

Pythonで「今の日付(年月日)を取得したい!」という場面は、ログの記録やファイル名の自動生成など、実務でもよく出てきます。

しかし、初心者にとってはどのモジュールを使えばよいのか、どのような書き方が最適なのか悩むところです。

この記事では、Pythonでの年月日(Year, Month, Day)を取得する基本的な方法を、サンプルコードと一緒にわかりやすく紹介します。

スポンサーリンク

方法1:datetimeモジュールの基本使用

最も基本的な日付取得

datetimeモジュールは、Pythonで日時を扱う際の標準的な選択肢です。

基本的な使い方:

from datetime import datetime

# 現在の日時を取得
today = datetime.today()
print(today)
# 出力例: 2025-06-20 14:33:25.123456

# より正確な現在時刻を取得
now = datetime.now()
print(now)
# 出力例: 2025-06-20 14:33:25.123456

datetime.today()とdatetime.now()の違い:

メソッド説明用途
datetime.today()ローカル時刻を取得一般的な日付取得
datetime.now()より正確な現在時刻タイムスタンプが重要な場合
datetime.now(tz)タイムゾーン指定可能国際的なアプリケーション

年・月・日の個別取得

from datetime import datetime

today = datetime.today()

# 個別に年月日を取得
year = today.year
month = today.month  
day = today.day

print(f"年: {year}")
print(f"月: {month}")  
print(f"日: {day}")

# 出力例:
# 年: 2025
# 月: 6
# 日: 20

# 曜日情報も取得可能
weekday = today.weekday()  # 0=月曜日, 6=日曜日
weekday_name = today.strftime("%A")

print(f"曜日番号: {weekday}")
print(f"曜日名: {weekday_name}")

実用的な活用例

ファイル名の自動生成:

from datetime import datetime

def create_log_filename():
    """現在の日時を使ってログファイル名を生成"""
    now = datetime.now()
    filename = f"log_{now.year}{now.month:02d}{now.day:02d}_{now.hour:02d}{now.minute:02d}.txt"
    return filename

# 使用例
log_file = create_log_filename()
print(f"ログファイル名: {log_file}")
# 出力例: log_20250620_1433.txt

データベース用のタイムスタンプ:

from datetime import datetime

def get_timestamp_for_db():
    """データベース用のタイムスタンプを生成"""
    return datetime.now().isoformat()

# 使用例
timestamp = get_timestamp_for_db()
print(f"DBタイムスタンプ: {timestamp}")
# 出力例: 2025-06-20T14:33:25.123456

年・月・日を個別に取り出せるので、ファイル名やタイトルへの埋め込みに非常に便利です。次は、時間情報が不要な場合のより簡潔な方法を見ていきましょう。

方法2:dateモジュールでシンプルな日付取得

時間なしの日付のみ取得

時刻情報が不要で、日付だけを扱いたい場合はdateクラスが最適です。

基本的な使い方:

from datetime import date

# 今日の日付を取得
today = date.today()
print(today)
# 出力例: 2025-06-20

# 年月日の個別取得
print(f"年: {today.year}")    # 2025
print(f"月: {today.month}")   # 6  
print(f"日: {today.day}")     # 20

# 曜日の取得
print(f"曜日番号: {today.weekday()}")  # 0=月曜日, 6=日曜日
print(f"ISO曜日: {today.isoweekday()}")  # 1=月曜日, 7=日曜日

dateとdatetimeの使い分け

dateクラスの特徴:

  • メモリ使用量が少ない
  • 時刻情報を持たない
  • 日付の比較や計算がシンプル
  • データベースのDATE型との親和性

実用的な比較例:

from datetime import date, datetime
import sys

# メモリ使用量の比較
date_obj = date.today()
datetime_obj = datetime.now()

print(f"dateオブジェクトのサイズ: {sys.getsizeof(date_obj)} bytes")
print(f"datetimeオブジェクトのサイズ: {sys.getsizeof(datetime_obj)} bytes")

# 出力例:
# dateオブジェクトのサイズ: 32 bytes
# datetimeオブジェクトのサイズ: 48 bytes

実用的な活用例

日付ベースのディレクトリ作成:

from datetime import date
import os

def create_daily_directory():
    """今日の日付でディレクトリを作成"""
    today = date.today()
    dir_name = f"data_{today.year}_{today.month:02d}_{today.day:02d}"
    
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)
        print(f"ディレクトリを作成しました: {dir_name}")
    else:
        print(f"ディレクトリは既に存在します: {dir_name}")
    
    return dir_name

# 使用例
daily_dir = create_daily_directory()
# 出力例: ディレクトリを作成しました: data_2025_06_20

年齢計算の例:

from datetime import date

def calculate_age(birth_date):
    """生年月日から年齢を計算"""
    today = date.today()
    age = today.year - birth_date.year
    
    # 誕生日がまだ来ていない場合は1歳引く
    if today.month < birth_date.month or \
       (today.month == birth_date.month and today.day < birth_date.day):
        age -= 1
    
    return age

# 使用例
birth = date(1990, 3, 15)
age = calculate_age(birth)
print(f"年齢: {age}歳")

「時刻は不要で、日付だけ欲しい」という場面では、この方法がメモリ効率的でシンプルです。

次は、取得した日付を様々な形式で表示する方法を学びましょう。

方法3:文字列フォーマットによる表示形式の制御

strftimeによる書式指定

取得した日付を特定の形式で表示したい場合、strftimeメソッドが非常に便利です。

基本的な書式指定:

from datetime import datetime

now = datetime.now()

# さまざまなフォーマットで表示
print("基本形式:", now.strftime("%Y/%m/%d"))           # 2025/06/20
print("日本式:", now.strftime("%Y年%m月%d日"))          # 2025年06月20日
print("英語式:", now.strftime("%B %d, %Y"))           # June 20, 2025
print("時刻付き:", now.strftime("%Y-%m-%d %H:%M:%S"))   # 2025-06-20 14:33:25
print("12時間表示:", now.strftime("%Y/%m/%d %I:%M %p"))  # 2025/06/20 02:33 PM

主要な書式指定子一覧

書式意味出力例説明
%Y年(4桁)2025西暦年
%y年(2桁)25西暦年の下2桁
%m月(2桁)06ゼロ埋めあり
%d日(2桁)20ゼロ埋めあり
%B月名(英語)June完全な月名
%b月名(英語短縮)Jun3文字の月名
%A曜日名(英語)Friday完全な曜日名
%a曜日名(英語短縮)Fri3文字の曜日名
%H時(24時間)1400-23の範囲
%I時(12時間)0201-12の範囲
%M3300-59の範囲
%S2500-59の範囲
%pAM/PMPM午前/午後

実用的なフォーマット例

ログファイル用のタイムスタンプ:

from datetime import datetime

def create_log_entry(message):
    """ログエントリを作成"""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return f"[{timestamp}] {message}"

# 使用例
log_entry = create_log_entry("システム開始")
print(log_entry)
# 出力例: [2025-06-20 14:33:25] システム開始

レポート用の日付表示:

from datetime import datetime

def format_report_date():
    """レポート用の日付フォーマット"""
    now = datetime.now()
    
    # 複数のフォーマットを返す
    formats = {
        'iso': now.strftime("%Y-%m-%d"),
        'japanese': now.strftime("%Y年%m月%d日"),
        'english': now.strftime("%B %d, %Y"),
        'compact': now.strftime("%Y%m%d"),
        'timestamp': now.strftime("%Y%m%d_%H%M%S")
    }
    
    return formats

# 使用例
date_formats = format_report_date()
for format_name, formatted_date in date_formats.items():
    print(f"{format_name}: {formatted_date}")

# 出力例:
# iso: 2025-06-20
# japanese: 2025年06月20日  
# english: June 20, 2025
# compact: 20250620
# timestamp: 20250620_143325

国際化対応の日付表示:

from datetime import datetime
import locale

def format_localized_date():
    """ロケール対応の日付フォーマット"""
    now = datetime.now()
    
    try:
        # 日本語ロケールを設定(環境によって異なる)
        locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
        japanese_date = now.strftime("%Y年%m月%d日 (%A)")
    except locale.Error:
        # ロケールが設定できない場合は英語のまま
        japanese_date = now.strftime("%Y年%m月%d日 (%A)")
    
    return japanese_date

# 使用例
localized_date = format_localized_date()
print(f"ローカライズ日付: {localized_date}")

実用的な応用例とベストプラクティス

ファイル管理での活用

自動バックアップシステム:

from datetime import datetime, date
import shutil
import os

class BackupManager:
    """日付ベースのバックアップ管理クラス"""
    
    def __init__(self, source_dir, backup_dir):
        self.source_dir = source_dir
        self.backup_dir = backup_dir
    
    def create_backup(self):
        """現在の日時でバックアップを作成"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_name = f"backup_{timestamp}"
        backup_path = os.path.join(self.backup_dir, backup_name)
        
        try:
            shutil.copytree(self.source_dir, backup_path)
            print(f"バックアップ作成完了: {backup_path}")
            return backup_path
        except Exception as e:
            print(f"バックアップエラー: {e}")
            return None
    
    def cleanup_old_backups(self, keep_days=7):
        """古いバックアップを削除"""
        cutoff_date = date.today().replace(day=date.today().day - keep_days)
        
        for item in os.listdir(self.backup_dir):
            if item.startswith("backup_"):
                # ファイル名から日付を抽出
                try:
                    date_str = item.split("_")[1][:8]  # YYYYMMDD
                    backup_date = datetime.strptime(date_str, "%Y%m%d").date()
                    
                    if backup_date < cutoff_date:
                        backup_path = os.path.join(self.backup_dir, item)
                        shutil.rmtree(backup_path)
                        print(f"古いバックアップを削除: {item}")
                except Exception as e:
                    print(f"バックアップ削除エラー: {e}")

# 使用例
backup_manager = BackupManager("/path/to/source", "/path/to/backups")
backup_manager.create_backup()
backup_manager.cleanup_old_backups()

データ分析での活用

日次レポート生成:

from datetime import datetime, timedelta
import pandas as pd

class DailyReportGenerator:
    """日次レポート生成クラス"""
    
    def __init__(self):
        self.report_date = datetime.now().date()
    
    def generate_filename(self):
        """レポートファイル名を生成"""
        date_str = self.report_date.strftime("%Y%m%d")
        return f"daily_report_{date_str}.xlsx"
    
    def get_date_range(self, days_back=7):
        """指定日数前からの日付範囲を取得"""
        end_date = self.report_date
        start_date = end_date - timedelta(days=days_back)
        
        date_range = []
        current_date = start_date
        while current_date <= end_date:
            date_range.append(current_date)
            current_date += timedelta(days=1)
        
        return date_range
    
    def create_report_header(self):
        """レポートヘッダーを作成"""
        formatted_date = self.report_date.strftime("%Y年%m月%d日")
        weekday = self.report_date.strftime("%A")
        
        header = {
            'report_date': formatted_date,
            'weekday': weekday,
            'generated_at': datetime.now().isoformat(),
            'report_type': '日次売上レポート'
        }
        
        return header

# 使用例
report_gen = DailyReportGenerator()
filename = report_gen.generate_filename()
date_range = report_gen.get_date_range()
header = report_gen.create_report_header()

print(f"レポートファイル名: {filename}")
print(f"対象期間: {len(date_range)}日間")
print(f"レポートヘッダー: {header}")

Webアプリケーションでの活用

イベント管理システム:

from datetime import datetime, date, timedelta

class EventManager:
    """イベント管理クラス"""
    
    def __init__(self):
        self.events = []
    
    def add_event(self, title, event_date, description=""):
        """イベントを追加"""
        event = {
            'id': len(self.events) + 1,
            'title': title,
            'event_date': event_date,
            'description': description,
            'created_at': datetime.now(),
            'status': self.get_event_status(event_date)
        }
        self.events.append(event)
        return event
    
    def get_event_status(self, event_date):
        """イベントの状態を判定"""
        today = date.today()
        
        if event_date < today:
            return "終了"
        elif event_date == today:
            return "本日開催"
        elif event_date <= today + timedelta(days=7):
            return "間もなく開催"
        else:
            return "開催予定"
    
    def get_upcoming_events(self, days=30):
        """今後のイベントを取得"""
        cutoff_date = date.today() + timedelta(days=days)
        
        upcoming = [
            event for event in self.events 
            if event['event_date'] >= date.today() 
            and event['event_date'] <= cutoff_date
        ]
        
        return sorted(upcoming, key=lambda x: x['event_date'])
    
    def format_event_list(self, events):
        """イベントリストを整形"""
        if not events:
            return "予定されているイベントはありません。"
        
        formatted_list = []
        for event in events:
            date_str = event['event_date'].strftime("%Y年%m月%d日 (%A)")
            formatted_list.append(
                f"・{event['title']} - {date_str} [{event['status']}]"
            )
        
        return "\n".join(formatted_list)

# 使用例
event_mgr = EventManager()

# イベントを追加
event_mgr.add_event("チーム会議", date.today() + timedelta(days=1))
event_mgr.add_event("プロジェクト発表", date.today() + timedelta(days=14))
event_mgr.add_event("年末パーティー", date(2025, 12, 25))

# 今後のイベントを表示
upcoming = event_mgr.get_upcoming_events()
formatted_events = event_mgr.format_event_list(upcoming)
print("今後のイベント:")
print(formatted_events)

高度な日付処理とエラーハンドリング

タイムゾーン対応

タイムゾーンを考慮した日付取得:

from datetime import datetime, timezone, timedelta
import pytz  # pip install pytz が必要

def get_timezone_aware_date():
    """タイムゾーンを考慮した日付取得"""
    
    # UTC時刻
    utc_now = datetime.now(timezone.utc)
    print(f"UTC時刻: {utc_now}")
    
    # 日本時刻(JST)
    jst = timezone(timedelta(hours=9))
    jst_now = datetime.now(jst)
    print(f"JST時刻: {jst_now}")
    
    # pytzを使用した方法(より多くのタイムゾーンに対応)
    tokyo_tz = pytz.timezone('Asia/Tokyo')
    tokyo_now = datetime.now(tokyo_tz)
    print(f"東京時刻: {tokyo_now}")
    
    return {
        'utc': utc_now,
        'jst': jst_now,
        'tokyo': tokyo_now
    }

# 使用例
timezone_dates = get_timezone_aware_date()

エラーハンドリング

安全な日付処理:

from datetime import datetime, date
import logging

class SafeDateHandler:
    """安全な日付処理クラス"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
    
    def safe_parse_date(self, date_string, format_string="%Y-%m-%d"):
        """文字列を安全に日付に変換"""
        try:
            return datetime.strptime(date_string, format_string).date()
        except ValueError as e:
            self.logger.error(f"日付変換エラー: {date_string}, {e}")
            return None
    
    def safe_format_date(self, date_obj, format_string="%Y/%m/%d"):
        """日付を安全に文字列に変換"""
        try:
            if isinstance(date_obj, (date, datetime)):
                return date_obj.strftime(format_string)
            else:
                raise TypeError("date または datetime オブジェクトが必要です")
        except Exception as e:
            self.logger.error(f"日付フォーマットエラー: {date_obj}, {e}")
            return None
    
    def validate_date_range(self, start_date, end_date):
        """日付範囲の妥当性を検証"""
        try:
            if not isinstance(start_date, (date, datetime)):
                start_date = self.safe_parse_date(str(start_date))
            if not isinstance(end_date, (date, datetime)):
                end_date = self.safe_parse_date(str(end_date))
            
            if start_date and end_date:
                if start_date <= end_date:
                    return True, "有効な日付範囲です"
                else:
                    return False, "開始日が終了日より後になっています"
            else:
                return False, "日付の解析に失敗しました"
        
        except Exception as e:
            self.logger.error(f"日付範囲検証エラー: {e}")
            return False, f"検証エラー: {e}"

# 使用例
date_handler = SafeDateHandler()

# 安全な日付変換
parsed_date = date_handler.safe_parse_date("2025-06-20")
formatted_date = date_handler.safe_format_date(parsed_date, "%Y年%m月%d日")

print(f"変換結果: {formatted_date}")

# 日付範囲の検証
is_valid, message = date_handler.validate_date_range("2025-06-01", "2025-06-30")
print(f"範囲検証: {is_valid}, {message}")

パフォーマンスとベストプラクティス

効率的な日付処理

大量データでの日付処理最適化:

from datetime import datetime, date
import time

def benchmark_date_operations():
    """日付操作のベンチマーク"""
    
    # テスト用のデータ準備
    test_count = 100000
    
    # datetime.now() vs datetime.today()
    start_time = time.time()
    for _ in range(test_count):
        dt = datetime.now()
    now_time = time.time() - start_time
    
    start_time = time.time()
    for _ in range(test_count):
        dt = datetime.today()
    today_time = time.time() - start_time
    
    # date.today() のパフォーマンス
    start_time = time.time()
    for _ in range(test_count):
        d = date.today()
    date_time = time.time() - start_time
    
    print(f"datetime.now(): {now_time:.4f}秒")
    print(f"datetime.today(): {today_time:.4f}秒")
    print(f"date.today(): {date_time:.4f}秒")
    
    return {
        'datetime_now': now_time,
        'datetime_today': today_time,
        'date_today': date_time
    }

# 使用例
benchmark_results = benchmark_date_operations()

メモリ効率的な日付処理:

from datetime import date, datetime
import sys

def compare_memory_usage():
    """日付オブジェクトのメモリ使用量比較"""
    
    # 異なる日付オブジェクトのメモリ使用量
    date_obj = date.today()
    datetime_obj = datetime.now()
    date_string = str(date_obj)
    
    print(f"date object: {sys.getsizeof(date_obj)} bytes")
    print(f"datetime object: {sys.getsizeof(datetime_obj)} bytes")
    print(f"date string: {sys.getsizeof(date_string)} bytes")
    
    # 大量の日付オブジェクトを扱う場合の推奨事項
    print("\n推奨事項:")
    print("- 時刻が不要な場合は date を使用")
    print("- 文字列での保存は必要最小限に")
    print("- タイムスタンプが必要な場合のみ datetime を使用")

# 使用例
compare_memory_usage()

まとめ:効率的な日付処理のガイド

用途別の推奨方法

用途推奨メソッド理由
ログのタイムスタンプdatetime.now()精密な時刻情報が必要
ファイル名の日付date.today()シンプルで軽量
データベース保存datetime.now().isoformat()標準形式で互換性が高い
ユーザー表示strftime()読みやすい形式に変換
期間計算date.today()計算処理が軽量

開発効率を上げるコツ

よく使うフォーマットの関数化:

from datetime import datetime, date

class DateUtils:
    """日付ユーティリティクラス"""
    
    @staticmethod
    def get_today_string():
        """今日の日付を文字列で取得"""
        return date.today().strftime("%Y-%m-%d")
    
    @staticmethod
    def get_timestamp():
        """現在のタイムスタンプを取得"""
        return datetime.now().strftime("%Y%m%d_%H%M%S")
    
    @staticmethod
    def get_japanese_date():
        """日本語形式の日付を取得"""
        return date.today().strftime("%Y年%m月%d日")
    
    @staticmethod
    def get_iso_datetime():
        """ISO形式の日時を取得"""
        return datetime.now().isoformat()
    
    @staticmethod
    def get_log_timestamp():
        """ログ用のタイムスタンプを取得"""
        return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# 使用例
print("今日の日付:", DateUtils.get_today_string())
print("タイムスタンプ:", DateUtils.get_timestamp())
print("日本語日付:", DateUtils.get_japanese_date())
print("ISO形式:", DateUtils.get_iso_datetime())
print("ログ形式:", DateUtils.get_log_timestamp())

# 出力例:
# 今日の日付: 2025-06-20
# タイムスタンプ: 20250620_143325
# 日本語日付: 2025年06月20日
# ISO形式: 2025-06-20T14:33:25.123456
# ログ形式: 2025-06-20 14:33:25

設定ファイルでの日付フォーマット管理

設定可能な日付フォーマット:

import json
from datetime import datetime, date

class ConfigurableDateFormatter:
    """設定可能な日付フォーマッタ"""
    
    def __init__(self, config_file="date_config.json"):
        self.config = self.load_config(config_file)
    
    def load_config(self, config_file):
        """設定ファイルを読み込み"""
        default_config = {
            "date_formats": {
                "default": "%Y-%m-%d",
                "japanese": "%Y年%m月%d日",
                "us": "%m/%d/%Y",
                "european": "%d/%m/%Y",
                "iso": "%Y-%m-%d",
                "compact": "%Y%m%d"
            },
            "datetime_formats": {
                "default": "%Y-%m-%d %H:%M:%S",
                "iso": "%Y-%m-%dT%H:%M:%S",
                "log": "[%Y-%m-%d %H:%M:%S]",
                "filename": "%Y%m%d_%H%M%S"
            }
        }
        
        try:
            with open(config_file, 'r') as f:
                config = json.load(f)
            return {**default_config, **config}
        except FileNotFoundError:
            return default_config
    
    def format_date(self, date_obj=None, format_name="default"):
        """設定に基づいて日付をフォーマット"""
        if date_obj is None:
            date_obj = date.today()
        
        format_string = self.config["date_formats"].get(format_name, "%Y-%m-%d")
        return date_obj.strftime(format_string)
    
    def format_datetime(self, datetime_obj=None, format_name="default"):
        """設定に基づいて日時をフォーマット"""
        if datetime_obj is None:
            datetime_obj = datetime.now()
        
        format_string = self.config["datetime_formats"].get(format_name, "%Y-%m-%d %H:%M:%S")
        return datetime_obj.strftime(format_string)

# 使用例
formatter = ConfigurableDateFormatter()

# 様々な形式で現在の日付を表示
formats = ["default", "japanese", "us", "european", "compact"]
for fmt in formats:
    formatted = formatter.format_date(format_name=fmt)
    print(f"{fmt}: {formatted}")

# 出力例:
# default: 2025-06-20
# japanese: 2025年06月20日
# us: 06/20/2025
# european: 20/06/2025
# compact: 20250620

国際化対応の日付処理

多言語対応の日付表示:

from datetime import datetime, date
import calendar
import locale

class InternationalDateFormatter:
    """国際化対応の日付フォーマッタ"""
    
    def __init__(self):
        self.month_names = {
            'en': ['January', 'February', 'March', 'April', 'May', 'June',
                   'July', 'August', 'September', 'October', 'November', 'December'],
            'ja': ['1月', '2月', '3月', '4月', '5月', '6月',
                   '7月', '8月', '9月', '10月', '11月', '12月'],
            'fr': ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
                   'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']
        }
        
        self.weekday_names = {
            'en': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
            'ja': ['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'],
            'fr': ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']
        }
    
    def format_date_localized(self, date_obj=None, lang='en'):
        """ローカライズされた日付フォーマット"""
        if date_obj is None:
            date_obj = date.today()
        
        if lang not in self.month_names:
            lang = 'en'
        
        month_name = self.month_names[lang][date_obj.month - 1]
        weekday_name = self.weekday_names[lang][date_obj.weekday()]
        
        if lang == 'ja':
            return f"{date_obj.year}年{month_name}{date_obj.day}日 ({weekday_name})"
        elif lang == 'en':
            return f"{weekday_name}, {month_name} {date_obj.day}, {date_obj.year}"
        elif lang == 'fr':
            return f"{weekday_name} {date_obj.day} {month_name} {date_obj.year}"
        
        return str(date_obj)
    
    def get_all_formats(self, date_obj=None):
        """全ての言語形式で日付を取得"""
        if date_obj is None:
            date_obj = date.today()
        
        formats = {}
        for lang in self.month_names.keys():
            formats[lang] = self.format_date_localized(date_obj, lang)
        
        return formats

# 使用例
intl_formatter = InternationalDateFormatter()

all_formats = intl_formatter.get_all_formats()
for lang, formatted_date in all_formats.items():
    print(f"{lang}: {formatted_date}")

# 出力例:
# en: Friday, June 20, 2025
# ja: 2025年6月20日 (金曜日)
# fr: vendredi 20 juin 2025

エラーハンドリングのベストプラクティス

堅牢な日付処理システム:

from datetime import datetime, date
import logging
from typing import Optional, Union

class RobustDateProcessor:
    """堅牢な日付処理クラス"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        logging.basicConfig(level=logging.INFO)
    
    def safe_date_operation(self, operation, *args, **kwargs):
        """安全な日付操作の実行"""
        try:
            return operation(*args, **kwargs), None
        except Exception as e:
            error_msg = f"日付操作エラー: {e}"
            self.logger.error(error_msg)
            return None, error_msg
    
    def parse_flexible_date(self, date_input: Union[str, date, datetime]) -> Optional[date]:
        """柔軟な日付パース"""
        if isinstance(date_input, date):
            return date_input
        elif isinstance(date_input, datetime):
            return date_input.date()
        elif isinstance(date_input, str):
            # 複数のフォーマットを試行
            formats = [
                "%Y-%m-%d",
                "%Y/%m/%d", 
                "%d/%m/%Y",
                "%m/%d/%Y",
                "%Y%m%d",
                "%d-%m-%Y"
            ]
            
            for fmt in formats:
                try:
                    return datetime.strptime(date_input, fmt).date()
                except ValueError:
                    continue
            
            self.logger.error(f"日付パースに失敗: {date_input}")
            return None
        else:
            self.logger.error(f"サポートされていない日付形式: {type(date_input)}")
            return None
    
    def calculate_business_days(self, start_date: Union[str, date], 
                               end_date: Union[str, date]) -> Optional[int]:
        """営業日数の計算"""
        start = self.parse_flexible_date(start_date)
        end = self.parse_flexible_date(end_date)
        
        if not start or not end:
            return None
        
        if start > end:
            start, end = end, start
        
        business_days = 0
        current_date = start
        
        while current_date <= end:
            if current_date.weekday() < 5:  # 月曜日=0, 日曜日=6
                business_days += 1
            current_date = current_date.replace(day=current_date.day + 1)
        
        return business_days
    
    def format_with_fallback(self, date_obj: Union[str, date, datetime],
                           primary_format: str, 
                           fallback_format: str = "%Y-%m-%d") -> str:
        """フォールバック付きフォーマット"""
        parsed_date = self.parse_flexible_date(date_obj)
        
        if not parsed_date:
            return "Invalid Date"
        
        try:
            return parsed_date.strftime(primary_format)
        except ValueError:
            self.logger.warning(f"プライマリフォーマット失敗: {primary_format}")
            try:
                return parsed_date.strftime(fallback_format)
            except ValueError:
                return str(parsed_date)

# 使用例
processor = RobustDateProcessor()

# 柔軟な日付パース
test_dates = ["2025-06-20", "20/06/2025", "06/20/2025", "20250620"]
for test_date in test_dates:
    parsed = processor.parse_flexible_date(test_date)
    print(f"{test_date} → {parsed}")

# 営業日数計算
business_days = processor.calculate_business_days("2025-06-01", "2025-06-30")
print(f"営業日数: {business_days}日")

# フォールバック付きフォーマット
formatted = processor.format_with_fallback(
    date.today(), 
    "%Y年%m月%d日 (%A)",  # プライマリ
    "%Y-%m-%d"           # フォールバック
)
print(f"フォーマット結果: {formatted}")

コメント

タイトルとURLをコピーしました