Repository: plone/plone.restapi (language: python)

Issue:
Bug Report: Unexpected "Z" appended to API output
I updated `plone.restapi` version, I found the but for timezone on `@history` view. My env is JST(UTC+9). I look at this view as 9 hours later.

### Description: 
Currently, the plone.restapi package outputs datetime values with an appended "Z" at the end, indicating that the datetime is in UTC timezone. However, I think the original data is saved in local timezone as a Unix timestamp in milliseconds.

This behavior can be confusing for users because it is not clear whether the timestamp represents the local time or UTC. Therefore, it may be better to output the datetime value in a format that clearly indicates whether it is in local or UTC timezone.

### Steps to Reproduce: 
Make a request to the API that returns a datetime value.
Inspect the response body.
Expected behavior
The datetime value should be in a format that clearly indicates whether it is in local or UTC timezone.

### Actual behavior:
The datetime value has a "Z" appended at the end, which indicates that it is in UTC timezone. However, the original data is saved in local timezone as a Unix timestamp in milliseconds.

### Related PR:
https://github.com/plone/plone.restapi/pull/1531/files

### Environment
plone.restapi version: 8.35.2




Discussion / hints:
Hi @terapyon, I think you are correct that there is a bug here. The timestamp comes from CMFEditions which generates it using `time.time()`. The code you linked should be converting it to UTC using `dt.utcfromtimestamp` instead of `dt.fromtimestamp`.
@terapyon @davisagli See also:
- https://github.com/plone/plone.restapi/pull/1192
- https://github.com/plone/volto/issues/2597#issuecomment-895114458

Fix patch:
diff --git a/news/1647.bugfix b/news/1647.bugfix
new file mode 100644
index 0000000000..8c3ba08dab
--- /dev/null
+++ b/news/1647.bugfix
@@ -0,0 +1,1 @@
+Fix timezone of dates for revisions in the `@history` service. @davisagli
diff --git a/src/plone/restapi/services/history/get.py b/src/plone/restapi/services/history/get.py
index 18b71c1f0d..842785f849 100644
--- a/src/plone/restapi/services/history/get.py
+++ b/src/plone/restapi/services/history/get.py
@@ -1,4 +1,5 @@
 from datetime import datetime as dt
+from datetime import timezone
 from plone.app.layout.viewlets.content import ContentHistoryViewlet
 from plone.restapi.bbb import safe_text
 from plone.restapi.interfaces import ISerializeToJson
@@ -71,13 +72,9 @@ def reply(self):
             # Versioning entries use a timestamp,
             # workflow ISO formatted string
             if not isinstance(item["time"], str):
-                # Note that isoformat does not add the Z at the end of the string, The lack of the
-                # timezone specifier causes Intl (and derivative libraries) in the browser not to
-                # use local time, which is considered a bug in applications. Therefore we add the Z
-                # to the end to make sure that the date will be interpreted properly by the client.
-                item["time"] = dt.fromtimestamp(int(item["time"])).strftime(
-                    "%Y-%m-%dT%H:%M:%SZ"
-                )
+                item["time"] = dt.fromtimestamp(
+                    int(item["time"]), tz=timezone.utc
+                ).isoformat(timespec="seconds")
 
             # The create event has an empty 'action', but we like it to say
             # 'Create', alike the transition_title
diff --git a/src/plone/restapi/services/locking/__init__.py b/src/plone/restapi/services/locking/__init__.py
index a2529d8246..53fce1b03d 100644
--- a/src/plone/restapi/services/locking/__init__.py
+++ b/src/plone/restapi/services/locking/__init__.py
@@ -1,6 +1,7 @@
 """ Locking
 """
 from datetime import datetime
+from datetime import timezone
 from plone import api
 from plone.locking.interfaces import ILockable
 
@@ -20,7 +21,9 @@ def creation_date(timestamp):
     # timezone specifier causes Intl (and derivative libraries) in the browser not to
     # use local time, which is considered a bug in applications. Therefore we add the Z
     # to the end to make sure that the date will be interpreted properly by the client.
-    return datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%dT%H:%M:%SZ")
+    return datetime.fromtimestamp(timestamp, tz=timezone.utc).isoformat(
+        timespec="seconds"
+    )
 
 
 def lock_info(obj):


Test patch:
diff --git a/src/plone/restapi/tests/http-examples/collection.resp b/src/plone/restapi/tests/http-examples/collection.resp
index 740fc4bc7d..036a0bfd27 100644
--- a/src/plone/restapi/tests/http-examples/collection.resp
+++ b/src/plone/restapi/tests/http-examples/collection.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -96,7 +96,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {
         "@id": "http://localhost:55001/plone/doc1",
         "@type": "Document",
diff --git a/src/plone/restapi/tests/http-examples/collection_fullobjects.resp b/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
index b6c5da9d17..04b573bff3 100644
--- a/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
+++ b/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -96,7 +96,7 @@ Content-Type: application/json
             "allow_discussion": false,
             "changeNote": "",
             "contributors": [],
-            "created": "1995-07-31T13:45:00",
+            "created": "1995-07-31T13:45:00+00:00",
             "creators": [
                 "test_user_1_"
             ],
@@ -112,7 +112,7 @@ Content-Type: application/json
                 "locked": false,
                 "stealable": true
             },
-            "modified": "1995-07-31T17:30:00",
+            "modified": "1995-07-31T17:30:00+00:00",
             "next_item": {
                 "@id": "http://localhost:55001/plone/collection",
                 "@type": "Collection",
@@ -178,7 +178,7 @@ Content-Type: application/json
             "allow_discussion": false,
             "changeNote": "",
             "contributors": [],
-            "created": "1995-07-31T13:45:00",
+            "created": "1995-07-31T13:45:00+00:00",
             "creators": [
                 "test_user_1_"
             ],
@@ -194,7 +194,7 @@ Content-Type: application/json
                 "locked": false,
                 "stealable": true
             },
-            "modified": "1995-07-31T17:30:00",
+            "modified": "1995-07-31T17:30:00+00:00",
             "next_item": {
                 "@id": "http://localhost:55001/plone/doc2",
                 "@type": "Document",
@@ -262,7 +262,7 @@ Content-Type: application/json
             "allow_discussion": false,
             "changeNote": "",
             "contributors": [],
-            "created": "1995-07-31T13:45:00",
+            "created": "1995-07-31T13:45:00+00:00",
             "creators": [
                 "test_user_1_"
             ],
@@ -278,7 +278,7 @@ Content-Type: application/json
                 "locked": false,
                 "stealable": true
             },
-            "modified": "1995-07-31T17:30:00",
+            "modified": "1995-07-31T17:30:00+00:00",
             "next_item": {},
             "parent": {
                 "@id": "http://localhost:55001/plone",
@@ -316,7 +316,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {
         "@id": "http://localhost:55001/plone/doc1",
         "@type": "Document",
diff --git a/src/plone/restapi/tests/http-examples/content_get.resp b/src/plone/restapi/tests/http-examples/content_get.resp
index c2ce316883..9d876dccf3 100644
--- a/src/plone/restapi/tests/http-examples/content_get.resp
+++ b/src/plone/restapi/tests/http-examples/content_get.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "admin"
     ],
@@ -50,7 +50,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone/folder",
diff --git a/src/plone/restapi/tests/http-examples/content_get_folder.resp b/src/plone/restapi/tests/http-examples/content_get_folder.resp
index a1ab52dc22..c7e9f35e75 100644
--- a/src/plone/restapi/tests/http-examples/content_get_folder.resp
+++ b/src/plone/restapi/tests/http-examples/content_get_folder.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -79,7 +79,7 @@ Content-Type: application/json
     "language": "",
     "layout": "listing_view",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "nextPreviousEnabled": false,
     "next_item": {},
     "parent": {
diff --git a/src/plone/restapi/tests/http-examples/content_patch_representation.resp b/src/plone/restapi/tests/http-examples/content_patch_representation.resp
index 9f26814f27..0003cae47f 100644
--- a/src/plone/restapi/tests/http-examples/content_patch_representation.resp
+++ b/src/plone/restapi/tests/http-examples/content_patch_representation.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "admin"
     ],
@@ -50,7 +50,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone/folder",
diff --git a/src/plone/restapi/tests/http-examples/content_post.resp b/src/plone/restapi/tests/http-examples/content_post.resp
index d9930ffcfa..9cd542a495 100644
--- a/src/plone/restapi/tests/http-examples/content_post.resp
+++ b/src/plone/restapi/tests/http-examples/content_post.resp
@@ -35,7 +35,7 @@ Location: http://localhost:55001/plone/folder/my-document
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "admin"
     ],
@@ -51,7 +51,7 @@ Location: http://localhost:55001/plone/folder/my-document
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone/folder",
diff --git a/src/plone/restapi/tests/http-examples/document.resp b/src/plone/restapi/tests/http-examples/document.resp
index 46a8f7d793..c9347e6aa3 100644
--- a/src/plone/restapi/tests/http-examples/document.resp
+++ b/src/plone/restapi/tests/http-examples/document.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -50,7 +50,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/event.resp b/src/plone/restapi/tests/http-examples/event.resp
index d66635ce26..a8538c9fc6 100644
--- a/src/plone/restapi/tests/http-examples/event.resp
+++ b/src/plone/restapi/tests/http-examples/event.resp
@@ -38,7 +38,7 @@ Content-Type: application/json
     "contact_name": null,
     "contact_phone": null,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -57,7 +57,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "open_end": false,
     "parent": {
diff --git a/src/plone/restapi/tests/http-examples/expansion.resp b/src/plone/restapi/tests/http-examples/expansion.resp
index 46a8f7d793..c9347e6aa3 100644
--- a/src/plone/restapi/tests/http-examples/expansion.resp
+++ b/src/plone/restapi/tests/http-examples/expansion.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -50,7 +50,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/expansion_expanded.resp b/src/plone/restapi/tests/http-examples/expansion_expanded.resp
index c12bb51211..f83d9dd694 100644
--- a/src/plone/restapi/tests/http-examples/expansion_expanded.resp
+++ b/src/plone/restapi/tests/http-examples/expansion_expanded.resp
@@ -41,7 +41,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -57,7 +57,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp b/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
index e504dae3b0..2de0d77456 100644
--- a/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
+++ b/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
@@ -235,7 +235,7 @@ Content-Type: application/json
                     "actor": "test_user_1_",
                     "comments": "",
                     "review_state": "private",
-                    "time": "1995-07-31T17:30:00",
+                    "time": "1995-07-31T17:30:00+00:00",
                     "title": "Private"
                 }
             ],
@@ -261,7 +261,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -277,7 +277,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/file.resp b/src/plone/restapi/tests/http-examples/file.resp
index efc75551cb..4b463c60fc 100644
--- a/src/plone/restapi/tests/http-examples/file.resp
+++ b/src/plone/restapi/tests/http-examples/file.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -52,7 +52,7 @@ Content-Type: application/json
     "language": "",
     "layout": "file_view",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/folder.resp b/src/plone/restapi/tests/http-examples/folder.resp
index b2aac1e5da..7a41f8227d 100644
--- a/src/plone/restapi/tests/http-examples/folder.resp
+++ b/src/plone/restapi/tests/http-examples/folder.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -65,7 +65,7 @@ Content-Type: application/json
     "language": "",
     "layout": "listing_view",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "nextPreviousEnabled": false,
     "next_item": {},
     "parent": {
diff --git a/src/plone/restapi/tests/http-examples/history_get.resp b/src/plone/restapi/tests/http-examples/history_get.resp
index 7819c1085f..9b3aae1c11 100644
--- a/src/plone/restapi/tests/http-examples/history_get.resp
+++ b/src/plone/restapi/tests/http-examples/history_get.resp
@@ -13,7 +13,7 @@ Content-Type: application/json
         },
         "comments": "Initial version",
         "may_revert": true,
-        "time": "1995-07-31T17:30:00Z",
+        "time": "1995-07-31T17:30:00+00:00",
         "transition_title": "Edited",
         "type": "versioning",
         "version": 0
@@ -29,7 +29,7 @@ Content-Type: application/json
         "comments": "",
         "review_state": "private",
         "state_title": "Private",
-        "time": "1995-07-31T18:30:00Z",
+        "time": "1995-07-31T18:30:00+00:00",
         "transition_title": "Create",
         "type": "workflow"
     }
diff --git a/src/plone/restapi/tests/http-examples/image.resp b/src/plone/restapi/tests/http-examples/image.resp
index 4dfb1ad451..c2e13cbd1e 100644
--- a/src/plone/restapi/tests/http-examples/image.resp
+++ b/src/plone/restapi/tests/http-examples/image.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -111,7 +111,7 @@ Content-Type: application/json
     "language": "",
     "layout": "image_view",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/link.resp b/src/plone/restapi/tests/http-examples/link.resp
index 7f6165b777..76d990359a 100644
--- a/src/plone/restapi/tests/http-examples/link.resp
+++ b/src/plone/restapi/tests/http-examples/link.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -47,7 +47,7 @@ Content-Type: application/json
     "language": "",
     "layout": "link_redirect_view",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/lock.resp b/src/plone/restapi/tests/http-examples/lock.resp
index 28cdc4d5a3..bd896add6a 100644
--- a/src/plone/restapi/tests/http-examples/lock.resp
+++ b/src/plone/restapi/tests/http-examples/lock.resp
@@ -2,7 +2,7 @@ HTTP/1.1 200 OK
 Content-Type: application/json
 
 {
-    "created": "1995-07-31T17:30:00Z",
+    "created": "1995-07-31T17:30:00+00:00",
     "creator": "admin",
     "creator_name": "admin",
     "creator_url": "http://localhost:55001/plone/author/admin",
diff --git a/src/plone/restapi/tests/http-examples/lock_nonstealable_timeout.resp b/src/plone/restapi/tests/http-examples/lock_nonstealable_timeout.resp
index 61c7ecd9ad..04bc7b80f3 100644
--- a/src/plone/restapi/tests/http-examples/lock_nonstealable_timeout.resp
+++ b/src/plone/restapi/tests/http-examples/lock_nonstealable_timeout.resp
@@ -2,7 +2,7 @@ HTTP/1.1 200 OK
 Content-Type: application/json
 
 {
-    "created": "1995-07-31T17:30:00Z",
+    "created": "1995-07-31T17:30:00+00:00",
     "creator": "admin",
     "creator_name": "admin",
     "creator_url": "http://localhost:55001/plone/author/admin",
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
index a6ff5e542e..d537815afe 100644
--- a/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
@@ -38,7 +38,7 @@ Content-Type: application/json
         "UID": "00000000000000000000000000000001",
         "allow_discussion": false,
         "contributors": [],
-        "created": "1995-07-31T13:45:00",
+        "created": "1995-07-31T13:45:00+00:00",
         "creators": [
             "admin"
         ],
@@ -73,7 +73,7 @@ Content-Type: application/json
         },
         "layout": "folder_listing",
         "lock": {},
-        "modified": "1995-07-31T17:30:00",
+        "modified": "1995-07-31T17:30:00+00:00",
         "next_item": {
             "@id": "http://localhost:55001/plone/de",
             "@type": "LRF",
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
index 0b506e7ac3..801625f6d7 100644
--- a/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
@@ -38,7 +38,7 @@ Content-Type: application/json
         "UID": "00000000000000000000000000000001",
         "allow_discussion": false,
         "contributors": [],
-        "created": "1995-07-31T13:45:00",
+        "created": "1995-07-31T13:45:00+00:00",
         "creators": [
             "admin"
         ],
@@ -73,7 +73,7 @@ Content-Type: application/json
         },
         "layout": "folder_listing",
         "lock": {},
-        "modified": "1995-07-31T17:30:00",
+        "modified": "1995-07-31T17:30:00+00:00",
         "next_item": {
             "@id": "http://localhost:55001/plone/de",
             "@type": "LRF",
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
index abfbe7e93f..a421c0b009 100644
--- a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
@@ -104,7 +104,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -120,7 +120,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/newsitem.resp b/src/plone/restapi/tests/http-examples/newsitem.resp
index 0618088231..e1dab847dd 100644
--- a/src/plone/restapi/tests/http-examples/newsitem.resp
+++ b/src/plone/restapi/tests/http-examples/newsitem.resp
@@ -34,7 +34,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -116,7 +116,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/refresh_lock.resp b/src/plone/restapi/tests/http-examples/refresh_lock.resp
index 28cdc4d5a3..bd896add6a 100644
--- a/src/plone/restapi/tests/http-examples/refresh_lock.resp
+++ b/src/plone/restapi/tests/http-examples/refresh_lock.resp
@@ -2,7 +2,7 @@ HTTP/1.1 200 OK
 Content-Type: application/json
 
 {
-    "created": "1995-07-31T17:30:00Z",
+    "created": "1995-07-31T17:30:00+00:00",
     "creator": "admin",
     "creator_name": "admin",
     "creator_url": "http://localhost:55001/plone/author/admin",
diff --git a/src/plone/restapi/tests/http-examples/search_fullobjects.resp b/src/plone/restapi/tests/http-examples/search_fullobjects.resp
index 12674a345d..5c9fe7ebf3 100644
--- a/src/plone/restapi/tests/http-examples/search_fullobjects.resp
+++ b/src/plone/restapi/tests/http-examples/search_fullobjects.resp
@@ -37,7 +37,7 @@ Content-Type: application/json
             "allow_discussion": false,
             "changeNote": "",
             "contributors": [],
-            "created": "1995-07-31T13:45:00",
+            "created": "1995-07-31T13:45:00+00:00",
             "creators": [
                 "test_user_1_"
             ],
@@ -53,7 +53,7 @@ Content-Type: application/json
                 "locked": false,
                 "stealable": true
             },
-            "modified": "1995-07-31T17:30:00",
+            "modified": "1995-07-31T17:30:00+00:00",
             "next_item": {},
             "parent": {
                 "@id": "http://localhost:55001/plone",
diff --git a/src/plone/restapi/tests/http-examples/search_metadata_fields.resp b/src/plone/restapi/tests/http-examples/search_metadata_fields.resp
index f53b267077..b0a99393b5 100644
--- a/src/plone/restapi/tests/http-examples/search_metadata_fields.resp
+++ b/src/plone/restapi/tests/http-examples/search_metadata_fields.resp
@@ -7,9 +7,9 @@ Content-Type: application/json
         {
             "@id": "http://localhost:55001/plone/doc1",
             "@type": "Document",
-            "created": "1995-07-31T13:45:00",
+            "created": "1995-07-31T13:45:00+00:00",
             "description": "",
-            "modified": "1995-07-31T17:30:00",
+            "modified": "1995-07-31T17:30:00+00:00",
             "review_state": "private",
             "title": "Lorem Ipsum",
             "type_title": "Page"
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
index cbdda29f64..4d636bc252 100644
--- a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
@@ -55,7 +55,7 @@ Content-Type: application/json
                 "UID": "00000000000000000000000000000001",
                 "allow_discussion": false,
                 "contributors": [],
-                "created": "1995-07-31T13:45:00",
+                "created": "1995-07-31T13:45:00+00:00",
                 "creators": [
                     "admin"
                 ],
@@ -90,7 +90,7 @@ Content-Type: application/json
                 },
                 "layout": "folder_listing",
                 "lock": {},
-                "modified": "1995-07-31T17:30:00",
+                "modified": "1995-07-31T17:30:00+00:00",
                 "next_item": {
                     "@id": "http://localhost:55001/plone/de",
                     "@type": "LRF",
@@ -131,7 +131,7 @@ Content-Type: application/json
     "UID": "00000000000000000000000000000001",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "admin"
     ],
@@ -166,7 +166,7 @@ Content-Type: application/json
     },
     "layout": "folder_listing",
     "lock": {},
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {
         "@id": "http://localhost:55001/plone/de",
         "@type": "LRF",
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
index fdd9f28b64..9d40582315 100644
--- a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
@@ -55,7 +55,7 @@ Content-Type: application/json
                 "UID": "00000000000000000000000000000001",
                 "allow_discussion": false,
                 "contributors": [],
-                "created": "1995-07-31T13:45:00",
+                "created": "1995-07-31T13:45:00+00:00",
                 "creators": [
                     "admin"
                 ],
@@ -90,7 +90,7 @@ Content-Type: application/json
                 },
                 "layout": "folder_listing",
                 "lock": {},
-                "modified": "1995-07-31T17:30:00",
+                "modified": "1995-07-31T17:30:00+00:00",
                 "next_item": {
                     "@id": "http://localhost:55001/plone/de",
                     "@type": "LRF",
@@ -132,7 +132,7 @@ Content-Type: application/json
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -151,7 +151,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone/en",
diff --git a/src/plone/restapi/tests/http-examples/translated_messages_object_history.resp b/src/plone/restapi/tests/http-examples/translated_messages_object_history.resp
index d691c98e3a..af91bed838 100644
--- a/src/plone/restapi/tests/http-examples/translated_messages_object_history.resp
+++ b/src/plone/restapi/tests/http-examples/translated_messages_object_history.resp
@@ -13,7 +13,7 @@ Content-Type: application/json
         },
         "comments": "Versi\u00f3n inicial",
         "may_revert": true,
-        "time": "1995-07-31T17:30:00Z",
+        "time": "1995-07-31T17:30:00+00:00",
         "transition_title": "Editado",
         "type": "versioning",
         "version": 0
@@ -29,7 +29,7 @@ Content-Type: application/json
         "comments": "",
         "review_state": "private",
         "state_title": "Privado",
-        "time": "1995-07-31T18:30:00Z",
+        "time": "1995-07-31T18:30:00+00:00",
         "transition_title": "Crear",
         "type": "workflow"
     }
diff --git a/src/plone/restapi/tests/http-examples/translated_messages_object_workflow.resp b/src/plone/restapi/tests/http-examples/translated_messages_object_workflow.resp
index 4d4b4fdda6..f910df32b1 100644
--- a/src/plone/restapi/tests/http-examples/translated_messages_object_workflow.resp
+++ b/src/plone/restapi/tests/http-examples/translated_messages_object_workflow.resp
@@ -9,7 +9,7 @@ Content-Type: application/json
             "actor": "test_user_1_",
             "comments": "",
             "review_state": "private",
-            "time": "1995-07-31T17:30:00",
+            "time": "1995-07-31T17:30:00+00:00",
             "title": "Privado"
         }
     ],
diff --git a/src/plone/restapi/tests/http-examples/translations_link_on_post.resp b/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
index 1a7755fb8b..798d352197 100644
--- a/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
+++ b/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
@@ -38,7 +38,7 @@ Location: http://localhost:55001/plone/de/mydocument
     "allow_discussion": false,
     "changeNote": "",
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "admin"
     ],
@@ -57,7 +57,7 @@ Location: http://localhost:55001/plone/de/mydocument
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone/de",
diff --git a/src/plone/restapi/tests/http-examples/workflow_get.resp b/src/plone/restapi/tests/http-examples/workflow_get.resp
index 0236890e41..40627dcc25 100644
--- a/src/plone/restapi/tests/http-examples/workflow_get.resp
+++ b/src/plone/restapi/tests/http-examples/workflow_get.resp
@@ -9,7 +9,7 @@ Content-Type: application/json
             "actor": "test_user_1_",
             "comments": "",
             "review_state": "private",
-            "time": "1995-07-31T17:30:00",
+            "time": "1995-07-31T17:30:00+00:00",
             "title": "Private"
         }
     ],
diff --git a/src/plone/restapi/tests/http-examples/workflow_post.resp b/src/plone/restapi/tests/http-examples/workflow_post.resp
index 2d41b826c7..a637868bc3 100644
--- a/src/plone/restapi/tests/http-examples/workflow_post.resp
+++ b/src/plone/restapi/tests/http-examples/workflow_post.resp
@@ -6,6 +6,6 @@ Content-Type: application/json
     "actor": "admin",
     "comments": "",
     "review_state": "published",
-    "time": "1995-07-31T18:30:00",
+    "time": "1995-07-31T18:30:00+00:00",
     "title": "Published with accent \u00e9"
 }
diff --git a/src/plone/restapi/tests/http-examples/workflow_post_with_body.resp b/src/plone/restapi/tests/http-examples/workflow_post_with_body.resp
index 480352c9a3..02e08a0ec9 100644
--- a/src/plone/restapi/tests/http-examples/workflow_post_with_body.resp
+++ b/src/plone/restapi/tests/http-examples/workflow_post_with_body.resp
@@ -6,6 +6,6 @@ Content-Type: application/json
     "actor": "admin",
     "comments": "Publishing my folder...",
     "review_state": "published",
-    "time": "1995-07-31T18:30:00",
+    "time": "1995-07-31T18:30:00+00:00",
     "title": "Published with accent \u00e9"
 }
diff --git a/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp b/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
index 632f563ad2..32a97febf7 100644
--- a/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
+++ b/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000001",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -46,7 +46,7 @@ Content-Type: application/json
     "language": "",
     "layout": "document_view",
     "lock": {
-        "created": "1995-07-31T17:30:00Z",
+        "created": "1995-07-31T17:30:00+00:00",
         "creator": "admin",
         "creator_name": "admin",
         "creator_url": "http://localhost:55001/plone/author/admin",
@@ -57,7 +57,7 @@ Content-Type: application/json
         "timeout": 4294967280,
         "token": "0.12345678901234567-0.98765432109876543-00105A989226:1630609830.249"
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {
         "@id": "http://localhost:55001/plone/copy_of_document",
         "@type": "Document",
@@ -84,7 +84,7 @@ Content-Type: application/json
     "version": "current",
     "working_copy": {
         "@id": "http://localhost:55001/plone/copy_of_document",
-        "created": "1995-07-31T13:45:00",
+        "created": "1995-07-31T13:45:00+00:00",
         "creator_name": "admin",
         "creator_url": "http://localhost:55001/plone/author/admin",
         "title": "Test document"
diff --git a/src/plone/restapi/tests/http-examples/workingcopy_get.resp b/src/plone/restapi/tests/http-examples/workingcopy_get.resp
index 27b37f44b1..b41b07c4dc 100644
--- a/src/plone/restapi/tests/http-examples/workingcopy_get.resp
+++ b/src/plone/restapi/tests/http-examples/workingcopy_get.resp
@@ -4,7 +4,7 @@ Content-Type: application/json
 {
     "working_copy": {
         "@id": "http://localhost:55001/plone/copy_of_document",
-        "created": "1995-07-31T13:45:00",
+        "created": "1995-07-31T13:45:00+00:00",
         "creator_name": "admin",
         "creator_url": "http://localhost:55001/plone/author/admin",
         "title": "Test document"
diff --git a/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp b/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
index aa76ec7ac3..08598e4e28 100644
--- a/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
+++ b/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
@@ -33,7 +33,7 @@ Content-Type: application/json
     "UID": "SomeUUID000000000000000000000002",
     "allow_discussion": false,
     "contributors": [],
-    "created": "1995-07-31T13:45:00",
+    "created": "1995-07-31T13:45:00+00:00",
     "creators": [
         "test_user_1_"
     ],
@@ -49,7 +49,7 @@ Content-Type: application/json
         "locked": false,
         "stealable": true
     },
-    "modified": "1995-07-31T17:30:00",
+    "modified": "1995-07-31T17:30:00+00:00",
     "next_item": {},
     "parent": {
         "@id": "http://localhost:55001/plone",
@@ -76,7 +76,7 @@ Content-Type: application/json
     "version": "current",
     "working_copy": {
         "@id": "http://localhost:55001/plone/copy_of_document",
-        "created": "1995-07-31T13:45:00",
+        "created": "1995-07-31T13:45:00+00:00",
         "creator_name": "admin",
         "creator_url": "http://localhost:55001/plone/author/admin",
         "title": "Test document"
diff --git a/src/plone/restapi/tests/statictime.py b/src/plone/restapi/tests/statictime.py
index 55fddc6e7c..6357c19666 100644
--- a/src/plone/restapi/tests/statictime.py
+++ b/src/plone/restapi/tests/statictime.py
@@ -1,4 +1,5 @@
 from datetime import datetime
+from datetime import timezone
 from DateTime import DateTime
 from plone.app.discussion.comment import Comment
 from plone.app.layout.viewlets.content import ContentHistoryViewlet
@@ -70,8 +71,8 @@ def __exit__(self, _type, exc, _traceback):
 
     def __init__(
         self,
-        created=datetime(1995, 7, 31, 13, 45),
-        modified=datetime(1995, 7, 31, 17, 30),
+        created=datetime(1995, 7, 31, 13, 45, tzinfo=timezone.utc),
+        modified=datetime(1995, 7, 31, 17, 30, tzinfo=timezone.utc),
     ):
         self.static_created = created
         self.static_modified = modified