Python | ファイル操作など:timedelta

Python
スポンサーリンク

概要(timedelta は「時間差・期間」を安全に計算するための基本)

timedelta は「何日・何時間・何分」などの“時間の長さ”や“差”を表すオブジェクトです。date/datetime と足し引きでき、締め切り計算、経過時間の測定、遅延処理、定期スケジュールなどに使います。文字列や手計算ではなく、timedelta を使うことで「型に守られた」正確な時間計算ができます。

from datetime import datetime, timedelta

now = datetime.now()
deadline = now + timedelta(days=3, hours=2)  # 3日と2時間後
elapsed = datetime.now() - now               # 経過時間(timedelta)
print(deadline, elapsed)
Python

基本の作り方と足し引き(ここが重要)

timedelta の主な引数(単位をまとめて与える)

days、hours、minutes、seconds、weeks、microseconds などをキーワード引数で指定します。複数指定すると合算された「期間」になります。

from datetime import timedelta

span = timedelta(days=2, hours=3, minutes=30)   # 2日+3時間+30分
print(span)                                     # 2 days, 3:30:00
Python

date/datetime と加減算する(期限・リマインダー・遅延)

date/datetime に足せば「未来」、引けば「過去」。これが最もよく使うパターンです。

from datetime import date, datetime, timedelta

print(date.today() + timedelta(days=7))              # 1週間後(date)
print(datetime.now() - timedelta(hours=1, minutes=5))# 1時間5分前(datetime)
Python

2つの日時の差をとる(測定・監視の基本)

日時同士の差は timedelta になります。秒でほしいときは total_seconds() を使います。

from datetime import datetime, timedelta
import time

t0 = datetime.now()
time.sleep(0.2)
delta = datetime.now() - t0
print(delta, delta.total_seconds())  # 0:00:00.20..., 0.2...
Python

重要ポイントの深掘り(属性・演算・丸め)

days・seconds・microseconds と total_seconds の違い

timedelta は内部的に days、seconds、microseconds を持ちます(minutes/hours/weeks は合算されてここに正規化されます)。人間向けの合計秒は total_seconds() を使うのが確実です。

from datetime import timedelta

td = timedelta(days=1, hours=2, seconds=3)
print(td.days, td.seconds, td.microseconds)  # 1, 7203, 0
print(td.total_seconds())                    # 1*86400 + 7203 = 93603.0
Python

乗算・除算・比較(期間のスケールやしきい値判定)

timedelta は数値との乗算・除算、timedelta 同士の比較ができます。期間の倍増、均等分割、経過しきい値の判定などに便利です。

from datetime import timedelta

td = timedelta(minutes=15)
print(td * 2)                      # 30分
print(td / 3)                      # 5分(timedelta)
print(timedelta(hours=1) > td)     # True(1時間は15分より長い)
print(timedelta(hours=1) / td)     # 4.0(比率:4倍)
Python

時刻単体(time)との加算は不可。datetime を使う

time は「時刻のみ」なので、timedelta を直接足せません。日時の計算が必要なときは datetime にしてから加算します。

from datetime import datetime, time, timedelta

base = datetime.combine(datetime.today(), time(9, 0))
print(base + timedelta(minutes=45))  # 09:45 の datetime
Python

指定粒度に丸める(分・15分単位など)

分単位や 15 分単位に揃えたいときは total_seconds() を使って割り算→切り捨て(または四捨五入)→戻すのが定石です。

from datetime import datetime, timedelta
import math

def floor_to_minutes(dt: datetime, m: int) -> datetime:
    secs = dt.timestamp()
    step = m * 60
    return datetime.fromtimestamp((secs // step) * step)

dt = datetime.now()
print(floor_to_minutes(dt, 15))  # 15分刻みの下方向丸め
Python

タイムゾーン・日付またぎの注意(DST・月の長さ)

タイムゾーン付き datetime へ足すと「時計の時刻」が動く

aware な datetime(tzinfo あり)へ timedelta を足すと、そのタイムゾーンの規則に沿って時刻が変わります。夏時間(DST)越えでは「見かけの時刻」がズレることがあるため、保存は UTC、表示で変換が安全です。

from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo

utc = datetime(2025, 3, 30, 0, 0, tzinfo=timezone.utc)
jst = utc.astimezone(ZoneInfo("Asia/Tokyo"))
print(jst + timedelta(hours=1))  # 表示用は OK。保存は UTC が安全
Python

「1か月」や「末日」は timedelta では表せない

月は長さが可変(28~31日)なので「1か月後」は timedelta で表現できません。月単位の計算が必要なら「月を足すロジック」を自作するか、日付を文字列で管理するなど要件に応じた設計にします(実務では“基準日+日数”に落とすのが安全)。

実務での定番パターン(期限・レート制限・スケジュール)

期限切れ判定(締め切りに間に合っているか)

from datetime import datetime, timedelta

def is_expired(created: datetime, ttl_minutes: int) -> bool:
    return datetime.now() > created + timedelta(minutes=ttl_minutes)

print(is_expired(datetime.now() - timedelta(minutes=10), 5))  # True
Python

レート制限(一定間隔以上で実行)

from datetime import datetime, timedelta

class RateLimiter:
    def __init__(self, interval: timedelta):
        self.interval = interval
        self.last = None
    def allow(self) -> bool:
        now = datetime.now()
        if self.last is None or now - self.last >= self.interval:
            self.last = now
            return True
        return False

rl = RateLimiter(timedelta(seconds=2))
Python

毎日一定時刻のジョブ次回実行時刻を計算

from datetime import datetime, time, timedelta

def next_run(at: time) -> datetime:
    today_run = datetime.combine(datetime.today(), at)
    return today_run if datetime.now() <= today_run else today_run + timedelta(days=1)

print(next_run(time(9, 0)))
Python

経過時間の人間向け表示(X分Y秒)

from datetime import datetime
import time

start = datetime.now()
time.sleep(1.8)
delta = datetime.now() - start
mins = int(delta.total_seconds() // 60)
secs = int(delta.total_seconds() % 60)
print(f"{mins}{secs}秒")
Python

例題で身につける(定番から一歩先まで)

例題1:ログの「過去 N 分のみ」抽出

from datetime import datetime, timedelta

def filter_recent(records: list[tuple[datetime, str]], minutes: int) -> list[str]:
    cutoff = datetime.now() - timedelta(minutes=minutes)
    return [msg for ts, msg in records if ts >= cutoff]
Python

例題2:15分刻みのスロット生成(会議室予約など)

from datetime import datetime, time, timedelta

def slots(date_: datetime, start: time, end: time, step_minutes: int):
    cur = datetime.combine(date_.date(), start)
    end_dt = datetime.combine(date_.date(), end)
    step = timedelta(minutes=step_minutes)
    out = []
    while cur < end_dt:
        out.append(cur)
        cur += step
    return out

print(slots(datetime.now(), time(9), time(12), 15))
Python

例題3:CSV の処理時間タイマー(平均・最大)

from datetime import datetime, timedelta

def stats(durations: list[timedelta]) -> tuple[timedelta, timedelta]:
    total = sum((d for d in durations), timedelta(0))
    avg = total / len(durations) if durations else timedelta(0)
    return avg, max(durations) if durations else timedelta(0)
Python

例題4:締め切りまでの残りを「端数切り上げ分」で表示

from datetime import datetime, timedelta
import math

def remaining_ceil(deadline: datetime) -> str:
    secs = (deadline - datetime.now()).total_seconds()
    if secs <= 0:
        return "期限切れ"
    mins = math.ceil(secs / 60)
    return f"残り約{mins}分"
Python

まとめ

timedelta は「期間・差分」を型として扱える強力な基礎道具です。days/hours/minutes などを合算して作り、date/datetime と足し引きして期限・経過・スケジュールを安全に計算します。合計秒は total_seconds() を使い、乗除や比較でしきい値判定・スケール調整が自在。タイムゾーンを跨ぐ計算や月単位の扱いに注意し、保存は UTC、表示はローカルへ変換、月はロジックで対処する——この線を守れば、初心者でも時間計算を短く、正確に、実務品質で書けます。

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