Pythonのdatetimeモジュール完全ガイド – 日付・時刻の扱い方

python

「Pythonで今の日付や時刻を取得したい」
「ログファイルに記録する時刻を整形したい」
「2つの日付の差を計算したい」
「文字列で書かれた日付をプログラムで処理したい」

そんなときに使うのが、Pythonのdatetimeモジュールです。

datetimeモジュールは、日付や時刻を扱うためのPython標準ライブラリです。

Webアプリケーション、データ分析、ログ管理など、あらゆる場面で必要になる重要なツールです。

スポンサーリンク

この記事でわかること

  • datetimeモジュールの基本的な使い方
  • 現在の日付・時刻の取得方法
  • 日付のフォーマット変換(見やすい形に変更)
  • 文字列から日付への変換
  • 日付の計算(何日後、何時間前など)
  • 実際のプログラムでの活用例

datetimeモジュールとは?

datetimeが必要な理由

普通の文字列では困ること:

# 文字列だと計算ができない
date1 = "2024-01-15"
date2 = "2024-01-20"
# date2 - date1 = ?(計算できない)

datetimeオブジェクトなら:

from datetime import datetime

date1 = datetime(2024, 1, 15)
date2 = datetime(2024, 1, 20)
diff = date2 - date1
print(diff.days)  # 5(5日の差)

1-2. よく使うクラス

クラス用途
datetime日付と時刻2024-01-15 14:30:45
date日付のみ2024-01-15
time時刻のみ14:30:45
timedelta時間の差5日間、3時間

現在の日付・時刻を取得しよう

基本的な取得方法

from datetime import datetime

# 現在の日時を取得
now = datetime.now()
print(now)
# 結果例:2024-06-02 14:35:27.123456
print(type(now))
# 結果:<class 'datetime.datetime'>

日付のみ、時刻のみを取得

from datetime import datetime, date, time

# 現在の日付のみ
today = date.today()
print(today)  # 2024-06-02

# 現在の時刻のみ
current_time = datetime.now().time()
print(current_time)  # 14:35:27.123456

特定の日時を作成

# 特定の日時を指定
specific_datetime = datetime(2024, 12, 25, 10, 30, 0)
print(specific_datetime)  # 2024-12-25 10:30:00

# 日付のみ指定(時刻は00:00:00)
specific_date = datetime(2024, 12, 25)
print(specific_date)  # 2024-12-25 00:00:00

日時の情報を取り出そう

年月日・時分秒の取得

from datetime import datetime

now = datetime.now()
print(f"現在時刻: {now}")

# 年月日を取得
print(f"年: {now.year}")        # 例:2024
print(f"月: {now.month}")       # 例:6
print(f"日: {now.day}")         # 例:2

# 時分秒を取得
print(f"時: {now.hour}")        # 例:14
print(f"分: {now.minute}")      # 例:35
print(f"秒: {now.second}")      # 例:27
print(f"マイクロ秒: {now.microsecond}")  # 例:123456

曜日の取得

# 曜日を数字で取得(月曜日=0, 日曜日=6)
print(f"曜日(数字): {now.weekday()}")  # 例:6(日曜日)

# 曜日を日本語で表示
weekdays = ["月", "火", "水", "木", "金", "土", "日"]
print(f"曜日: {weekdays[now.weekday()]}曜日")  # 例:日曜日

その他の便利な情報

# ISO形式で出力
print(f"ISO形式: {now.isoformat()}")
# 例:2024-06-02T14:35:27.123456

# タイムスタンプ(1970年1月1日からの秒数)
print(f"タイムスタンプ: {now.timestamp()}")
# 例:1717310127.123456

日時をいろんな形式で表示しよう(strftime)

strftimeの基本

strftimeを使うと、日時を好きな形式の文字列に変換できます。

from datetime import datetime

now = datetime.now()

# 基本的な形式
print(now.strftime("%Y-%m-%d"))           # 2024-06-02
print(now.strftime("%Y/%m/%d"))           # 2024/06/02
print(now.strftime("%H:%M:%S"))           # 14:35:27
print(now.strftime("%Y-%m-%d %H:%M:%S"))  # 2024-06-02 14:35:27

よく使うフォーマット一覧

記号意味
%Y年(4桁)2024
%y年(2桁)24
%m月(01-12)06
%B月名(英語)June
%d日(01-31)02
%H時(00-23)14
%I時(01-12)02
%M分(00-59)35
%S秒(00-59)27
%A曜日名(英語)Sunday
%a曜日名(英語短縮)Sun

実用的なフォーマット例

from datetime import datetime

now = datetime.now()

# 日本でよく使われる形式
print(now.strftime("%Y年%m月%d日"))              # 2024年06月02日
print(now.strftime("%m/%d/%Y"))                 # 06/02/2024
print(now.strftime("%Y-%m-%d (%A)"))            # 2024-06-02 (Sunday)

# ログファイル用
print(now.strftime("[%Y-%m-%d %H:%M:%S]"))      # [2024-06-02 14:35:27]

# ファイル名用(特殊文字を避ける)
print(now.strftime("%Y%m%d_%H%M%S"))            # 20240602_143527

# 12時間表記
print(now.strftime("%Y/%m/%d %I:%M:%S %p"))     # 2024/06/02 02:35:27 PM

実際の使用例

from datetime import datetime

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

def generate_filename():
    """日付を含むファイル名を生成"""
    date_str = datetime.now().strftime("%Y%m%d")
    return f"report_{date_str}.txt"

# 使用例
print(create_log_entry("プログラム開始"))
# [2024-06-02 14:35:27] プログラム開始

print(generate_filename())
# report_20240602.txt

文字列を日時に変換しよう(strptime)

基本的な変換

from datetime import datetime

# 文字列をdatetimeオブジェクトに変換
date_str = "2024-06-15 10:30:00"
dt = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
print(dt)          # 2024-06-15 10:30:00
print(type(dt))    # <class 'datetime.datetime'>

いろんな形式の文字列を変換

# さまざまな形式の日付文字列
examples = [
    ("2024/06/15", "%Y/%m/%d"),
    ("15-Jun-2024", "%d-%b-%Y"),
    ("June 15, 2024", "%B %d, %Y"),
    ("2024-06-15T10:30:00", "%Y-%m-%dT%H:%M:%S"),
    ("20240615", "%Y%m%d")
]

for date_string, format_string in examples:
    dt = datetime.strptime(date_string, format_string)
    print(f"{date_string} → {dt}")

エラー処理

from datetime import datetime

def safe_parse_date(date_string, format_string):
    """安全に日付を変換する関数"""
    try:
        return datetime.strptime(date_string, format_string)
    except ValueError as e:
        print(f"日付の変換に失敗しました: {e}")
        return None

# 使用例
result = safe_parse_date("2024-13-45", "%Y-%m-%d")  # 無効な日付
if result:
    print(f"変換成功: {result}")
else:
    print("変換に失敗しました")

日付の計算をしよう(timedelta)

timedeltaの基本

from datetime import datetime, timedelta

now = datetime.now()
print(f"現在: {now}")

# 未来の日時を計算
tomorrow = now + timedelta(days=1)
next_week = now + timedelta(weeks=1)
next_month = now + timedelta(days=30)  # 約1ヶ月

print(f"明日: {tomorrow}")
print(f"来週: {next_week}")
print(f"来月: {next_month}")

過去の日時を計算

# 過去の日時を計算
yesterday = now - timedelta(days=1)
last_week = now - timedelta(weeks=1)
three_hours_ago = now - timedelta(hours=3)

print(f"昨日: {yesterday}")
print(f"先週: {last_week}")
print(f"3時間前: {three_hours_ago}")

timedeltaで指定できる単位

from datetime import timedelta

# さまざまな時間単位
td = timedelta(
    days=7,           # 日
    hours=3,          # 時間
    minutes=30,       # 分
    seconds=45,       # 秒
    microseconds=123, # マイクロ秒
    weeks=2           # 週
)

print(f"合計: {td}")
# 結果:21 days, 3:30:45.000123

日付の差を計算

from datetime import datetime

# 2つの日付の差を計算
start_date = datetime(2024, 1, 1)
end_date = datetime(2024, 6, 15)

diff = end_date - start_date
print(f"差: {diff}")                    # 166 days, 0:00:00
print(f"日数: {diff.days}")             # 166
print(f"秒数: {diff.seconds}")          # 0
print(f"総秒数: {diff.total_seconds()}") # 14342400.0

実用的な計算例

from datetime import datetime, timedelta

def calculate_age(birth_date):
    """年齢を計算する関数"""
    today = datetime.now()
    age = today - birth_date
    return age.days // 365  # 概算の年齢

def next_business_day(date_obj):
    """次の営業日を計算(土日を除く)"""
    next_day = date_obj + timedelta(days=1)
    while next_day.weekday() >= 5:  # 土曜日=5, 日曜日=6
        next_day += timedelta(days=1)
    return next_day

def days_until_deadline(deadline_str):
    """締切までの日数を計算"""
    deadline = datetime.strptime(deadline_str, "%Y-%m-%d")
    today = datetime.now()
    diff = deadline - today
    return diff.days

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

today = datetime.now()
next_biz = next_business_day(today)
print(f"次の営業日: {next_biz.strftime('%Y-%m-%d (%A)')}")

days_left = days_until_deadline("2024-12-31")
print(f"年末まで: {days_left}日")

実際のプログラムでの活用例

ログファイルの管理

from datetime import datetime
import os

class Logger:
    def __init__(self, log_dir="logs"):
        self.log_dir = log_dir
        # ログディレクトリが存在しない場合は作成
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
    
    def log(self, message, level="INFO"):
        """ログメッセージを記録"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {level}: {message}"
        
        # 日付ごとのログファイル
        date_str = datetime.now().strftime("%Y%m%d")
        log_file = os.path.join(self.log_dir, f"app_{date_str}.log")
        
        with open(log_file, "a", encoding="utf-8") as f:
            f.write(log_entry + "\n")
        
        print(log_entry)

# 使用例
logger = Logger()
logger.log("アプリケーション開始")
logger.log("ユーザーログイン", "INFO")
logger.log("エラーが発生しました", "ERROR")

営業時間の判定

from datetime import datetime, time

class BusinessHours:
    def __init__(self, open_time="09:00", close_time="18:00"):
        self.open_time = datetime.strptime(open_time, "%H:%M").time()
        self.close_time = datetime.strptime(close_time, "%H:%M").time()
    
    def is_open(self, check_time=None):
        """営業時間内かどうかを判定"""
        if check_time is None:
            check_time = datetime.now().time()
        
        # 週末は営業時間外
        if datetime.now().weekday() >= 5:  # 土日
            return False
        
        return self.open_time <= check_time <= self.close_time
    
    def next_open_time(self):
        """次の営業開始時間を計算"""
        now = datetime.now()
        
        # 今日の営業時間内なら今すぐ
        if self.is_open():
            return now
        
        # 営業時間後または週末なら次の営業日
        next_day = now + timedelta(days=1)
        while next_day.weekday() >= 5:  # 週末をスキップ
            next_day += timedelta(days=1)
        
        return datetime.combine(next_day.date(), self.open_time)

# 使用例
business = BusinessHours("09:00", "18:00")

if business.is_open():
    print("現在営業中です")
else:
    next_open = business.next_open_time()
    print(f"次の営業開始: {next_open.strftime('%Y-%m-%d %H:%M')}")

データ分析での日付処理

from datetime import datetime, timedelta
import csv

class SalesAnalyzer:
    def __init__(self):
        self.sales_data = []
    
    def add_sale(self, amount, date_str=None):
        """売上データを追加"""
        if date_str is None:
            sale_date = datetime.now()
        else:
            sale_date = datetime.strptime(date_str, "%Y-%m-%d")
        
        self.sales_data.append({
            'amount': amount,
            'date': sale_date
        })
    
    def get_sales_by_period(self, days=30):
        """指定期間の売上を取得"""
        end_date = datetime.now()
        start_date = end_date - timedelta(days=days)
        
        period_sales = []
        for sale in self.sales_data:
            if start_date <= sale['date'] <= end_date:
                period_sales.append(sale)
        
        return period_sales
    
    def monthly_summary(self, year, month):
        """月次売上サマリー"""
        monthly_sales = []
        total_amount = 0
        
        for sale in self.sales_data:
            if sale['date'].year == year and sale['date'].month == month:
                monthly_sales.append(sale)
                total_amount += sale['amount']
        
        return {
            'count': len(monthly_sales),
            'total': total_amount,
            'average': total_amount / len(monthly_sales) if monthly_sales else 0
        }

# 使用例
analyzer = SalesAnalyzer()
analyzer.add_sale(1000, "2024-06-01")
analyzer.add_sale(1500, "2024-06-02")
analyzer.add_sale(800, "2024-05-30")

# 過去30日の売上
recent_sales = analyzer.get_sales_by_period(30)
print(f"過去30日の売上件数: {len(recent_sales)}")

# 6月の売上サマリー
summary = analyzer.monthly_summary(2024, 6)
print(f"6月の売上: {summary}")

タイムゾーンの扱い方

タイムゾーンの基本

from datetime import datetime
from zoneinfo import ZoneInfo  # Python 3.9以降

# タイムゾーン付きの日時
tokyo_time = datetime.now(ZoneInfo("Asia/Tokyo"))
utc_time = datetime.now(ZoneInfo("UTC"))
ny_time = datetime.now(ZoneInfo("America/New_York"))

print(f"東京: {tokyo_time}")
print(f"UTC: {utc_time}")
print(f"ニューヨーク: {ny_time}")

Python 3.8以前での対応

from datetime import datetime, timezone, timedelta

# UTCタイムゾーン
utc_time = datetime.now(timezone.utc)
print(f"UTC: {utc_time}")

# 日本標準時(UTC+9)
jst = timezone(timedelta(hours=9))
jst_time = datetime.now(jst)
print(f"JST: {jst_time}")

タイムゾーン変換

from datetime import datetime
from zoneinfo import ZoneInfo

# UTC時刻を他のタイムゾーンに変換
utc_dt = datetime(2024, 6, 2, 12, 0, 0, tzinfo=ZoneInfo("UTC"))

tokyo_dt = utc_dt.astimezone(ZoneInfo("Asia/Tokyo"))
london_dt = utc_dt.astimezone(ZoneInfo("Europe/London"))

print(f"UTC: {utc_dt}")
print(f"東京: {tokyo_dt}")
print(f"ロンドン: {london_dt}")

よくある問題と解決方法

Q1: タイムゾーンなしとありの比較でエラー

症状:

from datetime import datetime
from zoneinfo import ZoneInfo

dt1 = datetime.now()  # タイムゾーンなし
dt2 = datetime.now(ZoneInfo("UTC"))  # タイムゾーンあり

# これはエラーになる
# diff = dt2 - dt1  # TypeError

解決方法:

# 片方にタイムゾーンを設定
dt1_utc = dt1.replace(tzinfo=ZoneInfo("UTC"))
diff = dt2 - dt1_utc

Q2: 文字列変換でエラー

症状:

# 無効な日付でエラー
datetime.strptime("2024-02-30", "%Y-%m-%d")  # ValueError

解決方法:

def safe_strptime(date_string, format_string):
    try:
        return datetime.strptime(date_string, format_string)
    except ValueError:
        print(f"無効な日付: {date_string}")
        return None

Q3: 月末日の計算

問題:

# 単純に30日を足すと月が変わってしまう可能性
date = datetime(2024, 1, 31)
next_month = date + timedelta(days=30)  # 不正確

解決方法:

from calendar import monthrange

def add_months(date, months):
    """月を正確に加算する関数"""
    year = date.year
    month = date.month + months
    
    # 年の調整
    while month > 12:
        year += 1
        month -= 12
    while month < 1:
        year -= 1
        month += 12
    
    # 月末日の調整
    max_day = monthrange(year, month)[1]
    day = min(date.day, max_day)
    
    return date.replace(year=year, month=month, day=day)

# 使用例
date = datetime(2024, 1, 31)
next_month = add_months(date, 1)
print(next_month)  # 2024-02-29(うるう年の調整)

パフォーマンスと最適化

大量データでの日付処理

from datetime import datetime
import time

# 大量の日付データを処理する場合
dates = ["2024-01-01", "2024-01-02", "2024-01-03"] * 1000

# 毎回strptimeを呼ぶ(遅い)
start = time.time()
for date_str in dates:
    dt = datetime.strptime(date_str, "%Y-%m-%d")
slow_time = time.time() - start

# フォーマットをキャッシュする(速い)
start = time.time()
format_str = "%Y-%m-%d"
for date_str in dates:
    dt = datetime.strptime(date_str, format_str)
fast_time = time.time() - start

print(f"通常: {slow_time:.4f}秒")
print(f"最適化: {fast_time:.4f}秒")

ISO形式の活用

# ISO形式は高速でパース可能
from datetime import datetime

# ISO形式での処理(推奨)
iso_string = "2024-06-02T14:30:00"
dt = datetime.fromisoformat(iso_string)

# 独自形式(避けたほうが良い)
custom_string = "02/06/2024 2:30 PM"
dt = datetime.strptime(custom_string, "%d/%m/%Y %I:%M %p")

まとめ

Pythonのdatetimeモジュールは、日付と時刻を扱うための強力で柔軟なツールです。

この記事のポイント:

  • datetime.now()で現在時刻を取得
  • strftime()で日時を文字列に変換
  • strptime()で文字列を日時に変換
  • timedeltaで日時の計算
  • 実際のアプリケーションでの活用方法

コメント

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