- Python
datetime is not JSON serializableの直し方
TypeError: Object of type datetime is not JSON serializable は、json.dumps が JSON に変換できない型(datetime など)の値を受け取ったときのエラーです。 JSON にあるのは文字列・数値・真偽値・null・配列・オブジェクトだけなので、日時は文字列に変える方法を自分で決める必要があります。
直し方は、json.dumps の default= に変換の関数を渡すことです。
import json, datetime as dt, decimal, uuid
def to_json(o):
if isinstance(o, (dt.datetime, dt.date, dt.time)):
return o.isoformat() # 2026-10-11T09:30:00+09:00
if isinstance(o, decimal.Decimal):
return str(o) # "1.10"(精度を保つ。数値にしたいなら float(o))
if isinstance(o, (set, frozenset)):
return sorted(o) # 配列に
if isinstance(o, uuid.UUID):
return str(o)
raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
json.dumps(data, default=to_json, ensure_ascii=False)
確認環境:Python 3.11、pandas 3.0.6、pydantic 2.13.3、Node.js 22(確認日 2026年10月11日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「datetime is not JSON serializableの直し方」
再現:JSON にできない型
| 型 | エラー |
|---|---|
datetime |
Object of type datetime is not JSON serializable |
date |
Object of type date is not JSON serializable |
time |
Object of type time is not JSON serializable |
Decimal(DB の金額など) |
Object of type Decimal is not JSON serializable |
set |
Object of type set is not JSON serializable |
UUID |
Object of type UUID is not JSON serializable |
bytes |
Object of type bytes is not JSON serializable |
pandas の Timestamp |
Object of type Timestamp is not JSON serializable |
DB から取得した行(日時は datetime、金額は Decimal)を、そのまま json.dumps すると、まとめてこのエラーになります。
落とし穴:default=str で済ませると、形が崩れる
検索するとよく見かける default=str は、エラーは消えますが、値の形が変わります。
json.dumps({"at": now, "price": Decimal("1.10"), "tags": {"a"}}, default=str)
{"at": "2026-10-11 09:30:00+09:00", "price": "1.10", "tags": "{'a'}"}
| 値 | default=str の結果 |
問題 |
|---|---|---|
| datetime | "2026-10-11 09:30:00+09:00" |
日付と時刻の間が空白(ISO 8601 の T ではない) |
| Decimal | "1.10" |
数値ではなく文字列になる(受け取る側が数値を期待していると困る) |
| set | "{'a'}" |
Python の表示がそのまま文字列に。受け取る側で配列として使えない |
set が "{'a'}" という文字列になるのは、ほぼ確実に不具合になります。何がどう変換されるかを自分で決めた default 関数を使います。
(上の to_json を使ったとき)
{"at": "2026-10-11T09:30:00+09:00", "day": "2026-10-11", "price": "1.10", "tags": ["a", "b"], "id": "12345678-1234-5678-1234-567812345678"}
日時の書き方:isoformat とタイムゾーン
| datetime | isoformat() |
|---|---|
| タイムゾーンあり(Asia/Tokyo) | 2026-10-11T09:30:00+09:00 |
| タイムゾーンなし(naive) | 2026-10-11T09:30:00(どこの時刻か分からない) |
UTC にして Z で表す |
2026-10-11T00:30:00Z(.replace("+00:00", "Z")) |
タイムゾーンの無い日時を JSON にすると、受け取る側の環境の時刻として解釈されます。 確認環境の Node.js(日本時間の環境)では、"2026-10-11T09:30:00" を new Date() で読むと、日本時間の 9:30(UTC の 0:30)になりました。受け取る側が UTC のサーバーなら、9 時間ずれます。API で日時を渡すなら、タイムゾーン付き(+09:00 か Z)で書きます。
読み込む側で datetime に戻す
d = json.loads(s)
type(d["at"]) # str(JSON から読むと文字列のまま)
dt.datetime.fromisoformat(d["at"]) # 2026-10-11 09:30:00+09:00
json.loads は、日時の文字列を自動では datetime に戻しません。 どのキーが日時かを知っている側で、fromisoformat で戻します。
Decimal は文字列か数値か
| 変換 | 結果 | 向いている場面 |
|---|---|---|
str(o) |
"1.10"(文字列) |
金額など、精度を落としたくない。受け取る側で Decimal に戻す |
float(o) |
1.1(数値) |
表示用。精度の誤差が許される |
float にすると、0.1 + 0.2 が 0.30000000000000004 になるような小数の誤差が入ります。金額は文字列で渡し、受け取る側の言語の Decimal 型(Java の BigDecimal など)で戻すのが安全です。
pandas の DataFrame
rec = df.to_dict("records")[0]
json.dumps(rec) # TypeError: Object of type Timestamp is not JSON serializable
df.to_json(orient="records", date_format="iso")
# [{"at":"2026-10-11T09:30:00.000","n":1}]
DataFrame は to_json を使うと、日時も ISO 形式に変換されます。 to_dict してから json.dumps すると、pandas の Timestamp 型のままなので、このエラーになりました。
ライブラリに任せる方法
| 方法 | 結果(確認環境) |
|---|---|
pydantic の model_dump_json() |
{"at":"2026-10-11T09:30:00","price":"1.10"}(datetime は ISO、Decimal は文字列) |
json.JSONEncoder を継承して default を書く |
何度も使うときに、エンコーダーとしてまとめる |
class AppEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, (dt.datetime, dt.date)):
return o.isoformat()
return super().default(o) # 対応しない型は、元どおりエラーにする
json.dumps(data, cls=AppEncoder)
対応しない型を super().default(o) でエラーに戻すのがポイントです(Python 公式ドキュメントの例と同じ形。bytes を渡すと Object of type bytes is not JSON serializable になりました)。何でも文字列にすると、default=str と同じ問題が起きます。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | どの型か | エラー文の Object of type ○○ |
| 2 | どこから来た値か | DB の行(datetime・Decimal)、pandas(Timestamp) |
| 3 | 変換の方法 | default= に関数を渡す(default=str は避ける) |
| 4 | 日時 | isoformat()、タイムゾーン付きで |
| 5 | Decimal | 金額は str、表示だけなら float |
| 6 | 読み込む側 | fromisoformat・Decimal(...) で戻す |
よくある質問
Q. NaN や Infinity は JSON にできますか。
A. Python の json.dumps は、float("nan") を NaN と書き出しました。NaN は JSON の仕様に無いため、Node.js の JSON.parse では "{"v":NaN}" is not valid JSON のエラーになりました。allow_nan=False にすると、書き出す時点で ValueError: Out of range float values are not JSON compliant にできます。
Q. bytes はどうしますか。
A. 画像などのバイナリは、base64.b64encode(o).decode() で文字列にしてから渡すのが一般的です。
まとめ
- JSON に無い型(datetime・Decimal・set・UUID)を
json.dumpsに渡したエラー default=に変換の関数を渡す。対応しない型は TypeError に戻すdefault=strは形が崩れる(日時が空白区切り、set が"{'a'}")- 日時は
isoformat()+タイムゾーン。タイムゾーン無しは受け取る側の時刻として解釈される - 金額の Decimal は文字列で渡すと精度が落ちない
- pandas は
to_json(date_format="iso")、pydantic はmodel_dump_json()
参考・出典
確認日はいずれも 2026年10月11日です。
- Python ドキュメント「json — JSON encoder and decoder」:https://docs.python.org/3/library/json.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「datetime is not JSON serializableの直し方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。