Python / LESSON 15 / PY15

Python:標準ライブラリ活用(datetime / os / json)

1学習の目的

2基礎解説

やりたいこと書き方結果
日時を作るdatetime(2026, 1, 15)2026年1月15日
日時→文字列d.strftime("%Y/%m/%d")2026/01/15
文字列→日時datetime.strptime(s, "%Y-%m-%d")日時オブジェクト
辞書⇔JSON文字列json.dumps / json.loads相互に変換
✅ 覚えるべき重要ポイント
  1. 日時の足し引きは timedelta(days=30)。日時同士を引くと timedelta が返り、.days で日数が取れる。
  2. strftime は「日時→文字列」、strptime は「文字列→日時」。p は parse(解析)の p と覚えると混同しない。
  3. 書式記号は %Y%m%d%H%M分。月と分はどちらもmだが大文字小文字で別物
  4. パスは os.path.join("data", "a.csv") で組み立てる。文字列を + でつなぐとOSごとの区切り文字の違いで壊れる。
  5. JSONで日本語を出すなら ensure_ascii=False が必須。末尾に s が付くのが文字列用(dumps/loads)、付かないのがファイル用(dump/load)。

現場使用例:ログのタイムスタンプ、締め日・納期の計算、設定ファイル(config.json)の読み書き、APIレスポンスの解析、保存先フォルダの自動作成。

from datetime import datetime, timedelta
import os
import json

d = datetime(2026, 1, 15)
print(d.strftime("%Y年%m月%d日"))     # 2026年01月15日

later = d + timedelta(days=30)
print(later.strftime("%Y/%m/%d"))     # 2026/02/14
print((later - d).days)               # 30

print(os.path.join("data", "sales.csv"))   # data/sales.csv

config = {"name": "田中", "age": 30}
text = json.dumps(config, ensure_ascii=False)
print(text)                            # {"name": "田中", "age": 30}
print(json.loads(text)["name"])        # 田中

3基本ドリル(10問)

PY15-D01 2026年1月15日の日時を作り、「2026年01月15日」の形式で出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 2026年01月15日

ヒント

from datetime import datetime してから datetime(2026, 1, 15)。表示は strftime("%Y年%m月%d日")。

模範解答
from datetime import datetime

d = datetime(2026, 1, 15)
print(d.strftime("%Y年%m月%d日"))
解説

%m や %d は2桁ゼロ埋めで出力される(1月→01)。ゼロを付けたくない場合は自分で int にして f-string で組み立てる。

PY15-D02 日時オブジェクトを文字列に変換するメソッドはどれか。
A. strptime B. strftime C. tostring D. format_date
選択★☆☆無料
期待される結果

解答 == B

ヒント

f は format(書式化)の f。

模範解答
B
解説

strftime = string format time(日時→文字列)、strptime = string parse time(文字列→日時)。方向を取り違えるのが最頻出のミス

PY15-D03 2026年1月15日の30日後を「2026/02/14」の形式で出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 2026/02/14

ヒント

timedelta(days=30) を足す。timedelta も datetime からインポートする。

模範解答
from datetime import datetime, timedelta

d = datetime(2026, 1, 15) + timedelta(days=30)
print(d.strftime("%Y/%m/%d"))
解説

月をまたぐ計算もうるう年もPythonが自動で処理する。日数を自分で31や28と数える必要はない。

PY15-D04 辞書をJSON文字列に変換するコードを完成させよ(日本語がそのまま出るようにすること)。 穴埋め★☆☆無料
コード
import json

config = {"name": "田中"}
print(json.____(config, ensure_ascii=False))
期待される結果

出力 == {"name": "田中"}

ヒント

「文字列に出力する」ほう。末尾に s が付く。

模範解答
print(json.dumps(config, ensure_ascii=False))
解説

dumps は dump string の略。ファイルに直接書くときは s の付かない dump を使う。

PY15-D05 json.dumpsensure_ascii=False を付けないと、日本語はどう出力されるか。
A. そのまま日本語 B. \u7530\u4e2d のようなエスケープ表記 C. 文字化けする D. エラーになる
選択★☆☆無料
期待される結果

解答 == B

ヒント

既定では ASCII 文字だけで表現しようとする。

模範解答
B
解説

データとしては正しく復元できるが人間が読めない。設定ファイルなど目視する用途では必ず ensure_ascii=False を付ける。

PY15-D06 2026年1月15日と2026年3月1日の差を日数で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 45

ヒント

日時同士を引き算し、結果の .days を取り出す。

模範解答
from datetime import datetime

a = datetime(2026, 1, 15)
b = datetime(2026, 3, 1)

print((b - a).days)
解説

引き算の結果は timedelta。.days を付けないと「45 days, 0:00:00」という表記になるので注意。

PY15-D07 文字列 "2026-01-15" を日時オブジェクトに変換するコードを完成させよ。 穴埋め★★☆無料
コード
from datetime import datetime

d = datetime.____("2026-01-15", "%Y-%m-%d")
print(d.strftime("%Y年%m月%d日"))
期待される結果

出力 == 2026年01月15日

ヒント

文字列を解析(parse)するほう。第2引数で元の文字列の形を教える。

模範解答
strptime
解説

第2引数は入力側の書式。CSVやAPIから来る日付は文字列なので、まずこれで日時に変換してから計算する。

PY15-D08 開いたファイルオブジェクトから直接JSONを読み込む関数はどれか。
A. json.loads B. json.load C. json.read D. json.parse
選択★★☆無料
期待される結果

解答 == B

ヒント

s が付くほうと付かないほう、どちらがファイル用か。

模範解答
B
解説

s あり=文字列(string)相手、s なし=ファイル相手。この1文字の違いだけなので、間違えたら思い出したい。

PY15-D09 path = "data/report.csv" からファイル名だけ拡張子を、この順に1行ずつ出力せよ。 コーディング★★☆無料
期待される結果

出力 == report.csv / .csv(2行)

ヒント

os.path.basename() と os.path.splitext()。splitext は (名前, 拡張子) のタプルを返す。

模範解答
import os

path = "data/report.csv"

print(os.path.basename(path))
print(os.path.splitext(path)[1])
解説

文字列を split("/") や split(".") で切るより確実で読みやすい。拡張子にドットが含まれる点に注意(".csv")。

PY15-D10 辞書 {"name": "田中", "age": 30} を "config.json" に保存し、読み返して名前と年齢を2行で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 田中 / 30(2行)

ヒント

保存は json.dump(config, f, ensure_ascii=False)、読み込みは json.load(f)。どちらも s は付かない。

模範解答
import json

config = {"name": "田中", "age": 30}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, ensure_ascii=False)

with open("config.json", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded["name"])
print(loaded["age"])
解説

読み返すと元の型が復元されるのがJSONの利点。CSVだと 30 が "30" になってしまうが、JSONなら数値のまま戻る。

4実践シナリオ(5問)

PY15-S01 【納期計算】注文日を2026年1月15日とし、items = [("ノートPC", 7), ("マウス", 3), ("特注品", 30)](商品名とリードタイム日数)から納期を求め、「ノートPC:2026/01/22(7日後)」の形式で3行出力せよ。 コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

注文日に timedelta(days=日数) を足す。f-string の中で strftime を使うときは引用符の種類を変える(外が " なら中は ')。

模範解答
from datetime import datetime, timedelta

order_date = datetime(2026, 1, 15)
items = [("ノートPC", 7), ("マウス", 3), ("特注品", 30)]

for name, days in items:
    due = order_date + timedelta(days=days)
    print(f"{name}:{due.strftime('%Y/%m/%d')}({days}日後)")
解説

月をまたぐ「特注品」も自動で2月14日になる。締め日・納期・有効期限の計算はすべてこの形で書ける。

PY15-S02 【日付文字列の一括変換】raw = ["2026-01-05", "2026-02-14", "2026-03-01"] を「2026年01月05日(月)」の形式に変換して3行出力せよ。曜日は WEEK = ["月", "火", "水", "木", "金", "土", "日"] から取得すること。 コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

strptime で日時に変換してから strftime で書式化する。曜日は d.weekday() が0(月曜)〜6(日曜)を返すので WEEK の添字に使える。

模範解答
from datetime import datetime

WEEK = ["月", "火", "水", "木", "金", "土", "日"]
raw = ["2026-01-05", "2026-02-14", "2026-03-01"]

for r in raw:
    d = datetime.strptime(r, "%Y-%m-%d")
    print(f"{d.strftime('%Y年%m月%d日')}({WEEK[d.weekday()]})")
解説

文字列 → 日時 → 別の文字列という変換は日常茶飯事。曜日名は環境によって英語になることがあるため、自前のリストで持つほうが確実。

PY15-S03 【設定ファイルの更新】settings = {"theme": "light", "font_size": 14} を "settings.json" に保存し、読み返して表示 → theme を "dark"、font_size を 16 に変更して保存し直し → もう一度読み返して表示せよ。
「初期設定:{...}」「変更後:{...}」「テーマ:dark」の3行。
コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

読み込んだ辞書はそのまま書き換えられる。保存 → 読み込み → 変更 → 保存 → 読み込みの順で処理する。

模範解答
import json

settings = {"theme": "light", "font_size": 14}

with open("settings.json", "w", encoding="utf-8") as f:
    json.dump(settings, f, ensure_ascii=False)

with open("settings.json", encoding="utf-8") as f:
    loaded = json.load(f)

print(f"初期設定:{loaded}")

loaded["theme"] = "dark"
loaded["font_size"] = 16

with open("settings.json", "w", encoding="utf-8") as f:
    json.dump(loaded, f, ensure_ascii=False)

with open("settings.json", encoding="utf-8") as f:
    final = json.load(f)

print(f"変更後:{final}")
print(f"テーマ:{final['theme']}")
解説

アプリの設定保存はほぼこの形。PY12ではconfig.pyに書いたが、JSONならプログラムから安全に書き換えられる点が違う。

PY15-S04 【拡張子ごとのフォルダ分け】files = ["report.csv", "photo.png", "data.csv", "memo.txt", "chart.png"] を拡張子ごとに分類し、実際にその名前のフォルダを作成せよ。「csv/ ← 2件」の形式で件数を出力し、最後に「作成したフォルダ:['csv', 'png', 'txt']」と出力すること(フォルダ名は昇順)。 コーディング★★★無料
期待される結果

出力4行が完全一致

ヒント

拡張子は os.path.splitext(name)[1] で取れるが先頭にドットが付くので .lstrip(".") で外す。件数は辞書で数え、フォルダ作成は os.makedirs(ext, exist_ok=True)。

模範解答
import os

files = ["report.csv", "photo.png", "data.csv", "memo.txt", "chart.png"]

groups = {}

for name in files:
    ext = os.path.splitext(name)[1].lstrip(".")
    groups[ext] = groups.get(ext, 0) + 1
    os.makedirs(ext, exist_ok=True)

for ext, count in groups.items():
    print(f"{ext}/ ← {count}件")

print(f"作成したフォルダ:{sorted(groups.keys())}")
解説

exist_ok=True を付けると既にフォルダがあってもエラーにならない。ダウンロードフォルダの自動整理など、実生活で今日から使えるスクリプトの原型。

PY15-S05 【APIレスポンスの解析】次のJSON文字列を解析せよ。
response = '{"status": 200, "data": {"users": [{"name": "田中", "age": 30}, {"name": "鈴木", "age": 25}]}}'
「ステータス:200」「ユーザー数:2人」「田中(30歳)」「鈴木(25歳)」「平均年齢:27.5歳」の5行を出力すること。
コーディング★★★無料
期待される結果

出力5行が完全一致

ヒント

json.loads で辞書にすると result["data"]["users"] のように階層をたどって取り出せる。年齢だけのリストは内包表記で作る。

模範解答
import json

response = '{"status": 200, "data": {"users": [{"name": "田中", "age": 30}, {"name": "鈴木", "age": 25}]}}'

result = json.loads(response)
users = result["data"]["users"]

print(f"ステータス:{result['status']}")
print(f"ユーザー数:{len(users)}人")

for u in users:
    print(f"{u['name']}({u['age']}歳)")

ages = [u["age"] for u in users]
print(f"平均年齢:{sum(ages) / len(ages)}歳")
解説

APIの応答はほぼこの形(辞書の中にリスト、リストの中に辞書)。階層が深くても、辞書とリストの組み合わせでしかないと分かれば怖くない。PY16でこれを本物のAPIから取得する。

5仕上げ課題

PY15-FINAL 【日次バックアップレポート】datetime・os・json をすべて使い、バックアップ対象を判定してJSONレポートを保存せよ。

BASE_DATE = datetime(2026, 1, 15) # 実行日として固定
LIMIT_DAYS = 7

files = [
  ("sales.csv", 120, "2026-01-14"),
  ("old_report.pdf", 2400, "2025-12-01"),
  ("memo.txt", 3, "2026-01-15"),
  ("archive.zip", 51200, "2026-01-09"),
] # (ファイル名, サイズKB, 更新日)


仕様:
① 更新日が LIMIT_DAYS 以内なら「[対象]」、超えていれば「[除外]」で表示
② 対象のファイル名と合計サイズを集計
③ "backup" フォルダを作成し、report_20260115.json という名前でレポートを保存
 (保存する辞書:date / count / total_kb / files)
④ 保存したJSONを読み返し、キーと値を1行ずつ表示

出力仕様(14行):
=== バックアップレポート 2026年01月15日 ===
[対象] sales.csv(120KB / 1日前)
[除外] old_report.pdf(45日前)
[対象] memo.txt(3KB / 0日前)
[対象] archive.zip(51,200KB / 6日前)
---
対象:3件 / 合計51,323KB
backup フォルダに report_20260115.json を保存しました
---
[JSONを読み返し]
date: 2026-01-15
count: 3
total_kb: 51323
files: ['sales.csv', 'memo.txt', 'archive.zip']
期待される結果

出力14行が完全一致

ヒント

更新日は文字列なので strptime で日時に変換してから (BASE_DATE - d).days で経過日数を求める。ファイル名は f"report_{BASE_DATE.strftime('%Y%m%d')}.json" で作り、保存先は os.path.join("backup", filename)。読み返しは for key, value in loaded.items(): で回す。

模範解答
import json
import os
from datetime import datetime

BASE_DATE = datetime(2026, 1, 15)
LIMIT_DAYS = 7

files = [
    ("sales.csv", 120, "2026-01-14"),
    ("old_report.pdf", 2400, "2025-12-01"),
    ("memo.txt", 3, "2026-01-15"),
    ("archive.zip", 51200, "2026-01-09"),
]

print(f"=== バックアップレポート {BASE_DATE.strftime('%Y年%m月%d日')} ===")

targets = []
total_kb = 0

for name, size, updated in files:
    d = datetime.strptime(updated, "%Y-%m-%d")
    days = (BASE_DATE - d).days

    if days <= LIMIT_DAYS:
        targets.append(name)
        total_kb += size
        print(f"[対象] {name}({size:,}KB / {days}日前)")
    else:
        print(f"[除外] {name}({days}日前)")

os.makedirs("backup", exist_ok=True)

report = {
    "date": BASE_DATE.strftime("%Y-%m-%d"),
    "count": len(targets),
    "total_kb": total_kb,
    "files": targets,
}

filename = f"report_{BASE_DATE.strftime('%Y%m%d')}.json"
path = os.path.join("backup", filename)

with open(path, "w", encoding="utf-8") as f:
    json.dump(report, f, ensure_ascii=False)

print("---")
print(f"対象:{len(targets)}件 / 合計{total_kb:,}KB")
print(f"backup フォルダに {filename} を保存しました")

print("---")
print("[JSONを読み返し]")

with open(path, encoding="utf-8") as f:
    loaded = json.load(f)

for key, value in loaded.items():
    print(f"{key}: {value}")
解説

日付で判定し、フォルダを作り、結果をJSONで残す——実務の定期実行スクリプトが備えるべき要素が全部入っている。ファイル名に日付を埋め込むのは実行日ごとに履歴を残す定番の手法で、後から「いつのレポートか」が一目で分かる。BASE_DATE を datetime.now() に差し替えれば、そのまま毎日動く本物のバックアップスクリプトになる。