日付と時刻の処理の要点
内容の確認日: 2026-10-04
この分野は『Python実践レシピ』の第 8 章 (日付と時刻の処理) に対応し、40 問中 2 問が出題されます (dateutil の節は出題範囲外)。datetime モジュールの計算と書式、タイムゾーンの扱いが中心です。
タイムゾーンを持たない naive な日時と、持っている aware な日時の違いは、実務でもトラブルになりやすいところです。どの操作で時刻が変わり、どの操作で変わらないかを整理しましょう。
date・datetime・timedelta
date は日付、time は時刻、datetime は日付と時刻を表し、どれもイミュータブルです。値を変えた新しいオブジェクトは replace() で作ります。timedelta は期間を表し、日付に足し引きできます。
timedelta は内部で日・秒・マイクロ秒に正規化されます。days は日の部分、seconds は 1 日未満の部分の秒数で、期間全体の秒数は total_seconds() で求めます。月や年の単位はありません (月によって日数が違うため)。
from datetime import date, datetime, timedeltad = date(2026, 1, 31)print(d + timedelta(days=30), d.weekday(), d.isoweekday())span = datetime(2026, 12, 1, 9, 0) - datetime(2026, 11, 30, 7, 30)print(span, span.days, span.seconds, span.total_seconds())print(datetime(2026, 12, 31, 23, 0) + timedelta(hours=2))print(d.replace(month=2, day=28))python3 main.py 2026-03-02 5 6 1 day, 1:30:00 1 5400 91800.0 2027-01-01 01:00:00 2026-02-28
weekday() は月曜日を 0、isoweekday() は月曜日を 1 とする曜日です。2026 年 1 月 31 日は土曜日なので、それぞれ 5 と 6 です。
文字列との変換
strftime(書式) は日時を文字列に、datetime.strptime(文字列, 書式) は文字列を日時に変換します (f が format、p が parse)。主な書式は %Y (4 桁の年)・%m (月)・%d (日)・%H (24 時間制の時)・%M (分)・%S (秒)・%a (曜日の略称) で、月日や時分は 0 埋めの 2 桁です。
ISO 8601 形式 (2026-12-01T09:00:00) との変換には、isoformat() と fromisoformat() が使えます。+09:00 のような UTC からの差を含む文字列からは、aware な日時が作られます。
from datetime import datetimedt = datetime.strptime("2026/12/01 09:05", "%Y/%m/%d %H:%M")print(dt.strftime("%m月%d日 %H時%M分"), dt.isoformat())aware = datetime.fromisoformat("2026-12-01T09:00:00+09:00")print(aware.tzinfo, aware.utcoffset())python3 main.py 12月01日 09時05分 2026-12-01T09:05:00 UTC+09:00 9:00:00
naive と aware、タイムゾーン
tzinfo を持たない日時を naive、持つ日時を aware と呼びます。naive な日時と aware な日時は大小比較できず TypeError になり (== は常に False)、引き算もできません。
タイムゾーンは、固定の差なら datetime.timezone(timedelta(hours=9)) や timezone.utc、地域のタイムゾーンなら zoneinfo.ZoneInfo("Asia/Tokyo") で表します。ZoneInfo は IANA タイムゾーンデータベースを使うので、夏時間 (DST) も自動で考慮されます。
2 つのメソッドの違いが重要です。
・replace(tzinfo=...): 時刻の値はそのままで、タイムゾーンの情報だけを付け替える (「この時刻はどのタイムゾーンの時刻か」を決める)
・astimezone(...): 同じ時点を別のタイムゾーンで表すように、時刻を変換する
from datetime import datetime, timezonefrom zoneinfo import ZoneInfonaive = datetime(2026, 7, 1, 12, 0)utc = naive.replace(tzinfo=timezone.utc)print(utc.astimezone(ZoneInfo("Asia/Tokyo")))print(utc.astimezone(ZoneInfo("America/New_York")))print(naive.replace(tzinfo=ZoneInfo("Asia/Tokyo")))tokyo = datetime(2026, 7, 1, 21, 0, tzinfo=ZoneInfo("Asia/Tokyo"))print(tokyo == utc, tokyo - utc)try: print(naive < utc)except TypeError: print("naive と aware は比較できない")python3 main.py 2026-07-01 21:00:00+09:00 2026-07-01 08:00:00-04:00 2026-07-01 12:00:00+09:00 True 0:00:00 naive と aware は比較できない
ニューヨークは 7 月は夏時間なので UTC からの差が -4 時間です (冬は -5 時間)。aware な日時同士の比較や引き算は、タイムゾーンを考慮して「同じ時点か」で判定されます。
現在の日時は datetime.now() で取得できますが、引数なしでは naive になります。タイムゾーン付きで取得するには datetime.now(timezone.utc) のように指定します。
time モジュール
time.time() はエポック (1970 年 1 月 1 日 0 時 UTC) からの経過秒数を浮動小数点数で返し、time.sleep(秒) は処理を一時停止します (小数も指定できます)。
処理時間を測るときは、time.time() ではなく time.perf_counter() を使います。time.time() はシステムの時刻に従うので、時刻の変更 (時刻合わせなど) の影響を受けますが、perf_counter() や monotonic() は影響を受けない単調増加の時計です。値そのものは日時を表さず、2 回の差で経過時間を求めます。
import timestart = time.perf_counter()time.sleep(0.1)elapsed = time.perf_counter() - startprint(type(time.time()).__name__, 0.1 <= elapsed < 1)print(time.strftime("%Y-%m-%d", time.gmtime(0)))python3 main.py float True 1970-01-01
試験でよくある引っかけ
timedeltaに月の単位はないtimedelta(months=1)はTypeErrorです。月単位の計算はreplaceで月を変えるか、サードパーティの dateutil を使います。secondsとtotal_seconds()secondsは 1 日に満たない部分の秒数だけです。期間全体の秒数はtotal_seconds()です。weekday()とisoweekday()月曜日は
weekday()では0、isoweekday()では1です。naive と aware の比較
大小比較は
TypeErrorになり、==は常にFalseです。replaceとastimezonereplace(tzinfo=...)は時刻を変えずにタイムゾーンを付け、astimezoneは時刻を変換します。固定の差のタイムゾーンと夏時間
timezone(timedelta(hours=-5))は夏時間を扱えません。地域のタイムゾーンはZoneInfoを使います。経過時間の計測
time.time()ではなく、時刻の変更の影響を受けないtime.perf_counter()を使います。
問題で確認する
この分野の問題を、解説つきで読めます (登録不要)。
出典・参考
- Python エンジニア育成推進協会「Python 実践試験」(出題範囲)
- Python ドキュメント「datetime」
- Python ドキュメント「zoneinfo」
- Python ドキュメント「time」
コード例は、実際に実行して結果を確認しています。