From abb84d9756c4ca5c6dcdcb857c19b33ebd90f8b3 Mon Sep 17 00:00:00 2001
From: Erik Montnemery <erik@montnemery.com>
Date: Wed, 27 Oct 2021 19:51:38 +0200
Subject: [PATCH] Serialize dates and times to isoformat (#58157)

---
 homeassistant/helpers/json.py | 10 +++++++---
 tests/helpers/test_json.py    | 37 ++++++++++++++++++-----------------
 2 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/homeassistant/helpers/json.py b/homeassistant/helpers/json.py
index 738f744194f..c581e5a9361 100644
--- a/homeassistant/helpers/json.py
+++ b/homeassistant/helpers/json.py
@@ -1,5 +1,5 @@
 """Helpers to help with encoding Home Assistant objects in JSON."""
-from datetime import datetime, timedelta
+import datetime
 import json
 from typing import Any
 
@@ -12,7 +12,7 @@ class JSONEncoder(json.JSONEncoder):
 
         Hand other objects to the original method.
         """
-        if isinstance(o, datetime):
+        if isinstance(o, datetime.datetime):
             return o.isoformat()
         if isinstance(o, set):
             return list(o)
@@ -30,8 +30,12 @@ class ExtendedJSONEncoder(JSONEncoder):
 
         Fall back to repr(o).
         """
-        if isinstance(o, timedelta):
+        if isinstance(o, datetime.timedelta):
             return {"__type": str(type(o)), "total_seconds": o.total_seconds()}
+        if isinstance(o, datetime.datetime):
+            return o.isoformat()
+        if isinstance(o, (datetime.date, datetime.time)):
+            return {"__type": str(type(o)), "isoformat": o.isoformat()}
         try:
             return super().default(o)
         except TypeError:
diff --git a/tests/helpers/test_json.py b/tests/helpers/test_json.py
index 076af218676..4968c872946 100644
--- a/tests/helpers/test_json.py
+++ b/tests/helpers/test_json.py
@@ -1,5 +1,5 @@
 """Test Home Assistant remote methods and classes."""
-from datetime import timedelta
+import datetime
 
 import pytest
 
@@ -8,9 +8,10 @@ from homeassistant.helpers.json import ExtendedJSONEncoder, JSONEncoder
 from homeassistant.util import dt as dt_util
 
 
-def test_json_encoder(hass):
-    """Test the JSON Encoder."""
-    ha_json_enc = JSONEncoder()
+@pytest.mark.parametrize("encoder", (JSONEncoder, ExtendedJSONEncoder))
+def test_json_encoder(hass, encoder):
+    """Test the JSON encoders."""
+    ha_json_enc = encoder()
     state = core.State("test.test", "hello")
 
     # Test serializing a datetime
@@ -24,22 +25,21 @@ def test_json_encoder(hass):
     # Test serializing an object which implements as_dict
     assert ha_json_enc.default(state) == state.as_dict()
 
+
+def test_json_encoder_raises(hass):
+    """Test the JSON encoder raises on unsupported types."""
+    ha_json_enc = JSONEncoder()
+
     # Default method raises TypeError if non HA object
     with pytest.raises(TypeError):
         ha_json_enc.default(1)
 
 
-def test_trace_json_encoder(hass):
-    """Test the Trace JSON Encoder."""
+def test_extended_json_encoder(hass):
+    """Test the extended JSON encoder."""
     ha_json_enc = ExtendedJSONEncoder()
-    state = core.State("test.test", "hello")
-
-    # Test serializing a datetime
-    now = dt_util.utcnow()
-    assert ha_json_enc.default(now) == now.isoformat()
-
     # Test serializing a timedelta
-    data = timedelta(
+    data = datetime.timedelta(
         days=50,
         seconds=27,
         microseconds=10,
@@ -53,12 +53,13 @@ def test_trace_json_encoder(hass):
         "total_seconds": data.total_seconds(),
     }
 
-    # Test serializing a set()
-    data = {"milk", "beer"}
-    assert sorted(ha_json_enc.default(data)) == sorted(data)
+    # Test serializing a time
+    o = datetime.time(7, 20)
+    assert ha_json_enc.default(o) == {"__type": str(type(o)), "isoformat": "07:20:00"}
 
-    # Test serializong object which implements as_dict
-    assert ha_json_enc.default(state) == state.as_dict()
+    # Test serializing a date
+    o = datetime.date(2021, 12, 24)
+    assert ha_json_enc.default(o) == {"__type": str(type(o)), "isoformat": "2021-12-24"}
 
     # Default method falls back to repr(o)
     o = object()
-- 
GitLab