Repository: equinor/fmu-dataio

Issue:
Remove `NaiveDateTime` and normalize to UTC
Context: https://equinor.slack.com/archives/C06E3UTGTEV/p1744788858389449

https://github.com/equinor/fmu-dataio/blob/8d05c6e946c2539cb75681fb6010582616ab6419/src/fmu/dataio/_models/fmu_results/data.py#L25-L36

This should require normalizing timestamps to UTC which is the sane thing to do anyway.

Discussion:
@tnatt: Normalizing these dates to UTC will be difficult and has unknown implications. We would need to lookup the timezone for the specific field before doing it. Also a lot of the data produced will be tabular data containing dates without timezones, and linking these dates together if one input is normalized to UTC and one is not will be challenging.

We decided to take the simple road now to change the format of these fields to `iso-date-time` instead of `datetime` to pass validation in `ajv.`

Solution patch:
diff --git a/examples/example_metadata/fmu_case.yml b/examples/example_metadata/fmu_case.yml
index 8fd0797c9..a22e4816d 100644
--- a/examples/example_metadata/fmu_case.yml
+++ b/examples/example_metadata/fmu_case.yml
@@ -32,7 +32,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:28.510327Z'
+- datetime: '2025-05-07T18:42:19.716702Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/polygons_field_outline.yml b/examples/example_metadata/polygons_field_outline.yml
index 88c4ea4f8..583af4718 100644
--- a/examples/example_metadata/polygons_field_outline.yml
+++ b/examples/example_metadata/polygons_field_outline.yml
@@ -98,7 +98,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:31.981876Z'
+- datetime: '2025-05-07T18:42:23.140379Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/polygons_field_region.yml b/examples/example_metadata/polygons_field_region.yml
index 0b8314b64..2c4a278c3 100644
--- a/examples/example_metadata/polygons_field_region.yml
+++ b/examples/example_metadata/polygons_field_region.yml
@@ -98,7 +98,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:31.957233Z'
+- datetime: '2025-05-07T18:42:23.115695Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/preprocessed_surface_depth.yml b/examples/example_metadata/preprocessed_surface_depth.yml
index 416f3ef5b..9c11c729e 100644
--- a/examples/example_metadata/preprocessed_surface_depth.yml
+++ b/examples/example_metadata/preprocessed_surface_depth.yml
@@ -80,7 +80,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:37.410235Z'
+- datetime: '2025-05-07T18:42:27.997499Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/surface_depth.yml b/examples/example_metadata/surface_depth.yml
index ca75c2779..034ed6128 100644
--- a/examples/example_metadata/surface_depth.yml
+++ b/examples/example_metadata/surface_depth.yml
@@ -95,7 +95,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:39.334086Z'
+- datetime: '2025-05-07T18:42:29.593855Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/surface_fluid_contact.yml b/examples/example_metadata/surface_fluid_contact.yml
index 8c3ae57fb..14502e44f 100644
--- a/examples/example_metadata/surface_fluid_contact.yml
+++ b/examples/example_metadata/surface_fluid_contact.yml
@@ -98,7 +98,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:39.385663Z'
+- datetime: '2025-05-07T18:42:29.649618Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/surface_seismic_amplitude.yml b/examples/example_metadata/surface_seismic_amplitude.yml
index 94c7779e2..5b4ebbfae 100644
--- a/examples/example_metadata/surface_seismic_amplitude.yml
+++ b/examples/example_metadata/surface_seismic_amplitude.yml
@@ -116,7 +116,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:39.438641Z'
+- datetime: '2025-05-07T18:42:29.705339Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/examples/example_metadata/table_inplace_volumes.yml b/examples/example_metadata/table_inplace_volumes.yml
index 018bb3f5c..68da10e86 100644
--- a/examples/example_metadata/table_inplace_volumes.yml
+++ b/examples/example_metadata/table_inplace_volumes.yml
@@ -103,7 +103,7 @@ masterdata:
       uuid: ad214d85-8a1d-19da-e053-c918a4889310
 source: fmu
 tracklog:
-- datetime: '2025-05-12T07:36:43.576954Z'
+- datetime: '2025-05-07T18:42:33.609572Z'
   event: created
   sysinfo:
     fmu-dataio:
diff --git a/schemas/0.11.0/fmu_results.json b/schemas/0.11.0/fmu_results.json
index 4489ca448..8369224c6 100644
--- a/schemas/0.11.0/fmu_results.json
+++ b/schemas/0.11.0/fmu_results.json
@@ -9649,7 +9649,7 @@
           "examples": [
             "2020-10-28T14:28:02"
           ],
-          "format": "date-time",
+          "format": "iso-date-time",
           "title": "Value",
           "type": "string"
         }
diff --git a/src/fmu/dataio/_models/fmu_results/data.py b/src/fmu/dataio/_models/fmu_results/data.py
index 891886e80..4dbaa97f8 100644
--- a/src/fmu/dataio/_models/fmu_results/data.py
+++ b/src/fmu/dataio/_models/fmu_results/data.py
@@ -32,7 +32,14 @@ class Timestamp(BaseModel):
     )
     """A string label corresponding to the timestamp."""
 
-    value: NaiveDatetime | AwareDatetime = Field(examples=["2020-10-28T14:28:02"])
+    # pydantic sets the format of the below field to "datetime".
+    # But "datetime" requires timezones and will fail in ajv validation.
+    # Workaround is to use the "iso-date-time" format instead.
+    # related pydantic issue #9518
+    value: NaiveDatetime | AwareDatetime = Field(
+        examples=["2020-10-28T14:28:02"],
+        json_schema_extra={"format": "iso-date-time"},
+    )
     """A datetime representation."""
 
 


Test patch:
diff --git a/tests/test_schema/test_pydantic_logic.py b/tests/test_schema/test_pydantic_logic.py
index e0055c6aa..34bc58c3d 100644
--- a/tests/test_schema/test_pydantic_logic.py
+++ b/tests/test_schema/test_pydantic_logic.py
@@ -7,7 +7,7 @@ from typing import Literal, get_args, get_origin
 import pytest
 from pydantic import ValidationError
 
-from fmu.dataio._models import FmuResults
+from fmu.dataio._models import FmuResults, FmuResultsSchema
 from fmu.dataio._models.fmu_results import data, enums
 
 from ..utils import _get_pydantic_models_from_annotation, _metadata_examples
@@ -540,3 +540,13 @@ def test_fmu_iteration_set_from_fmu_ensemble(metadata_examples):
     assert hasattr(model.root.fmu, "iteration")
     assert model.root.fmu.iteration == model.root.fmu.ensemble
     assert model.root.fmu.iteration.name == "pytest"
+
+
+def test_isodatetime_format_for_time():
+    """Test that the format for timestamps is set to iso-date-time
+    instead of datetime that pydantic resolves it to."""
+
+    schema = FmuResultsSchema.dump()
+    timestamp_value = schema["$defs"]["Timestamp"]["properties"]["value"]
+
+    assert timestamp_value["format"] == "iso-date-time"