Skip to content

Commit

Permalink
FIX: Make FMUDateTime.value a proper datetime
Browse files Browse the repository at this point in the history
  • Loading branch information
mferrera committed Apr 5, 2024
1 parent 5482912 commit d07f923
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 125 deletions.
1 change: 1 addition & 0 deletions schema/definitions/0.8.0/schema/fmu_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,7 @@
"value": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
Expand Down
68 changes: 0 additions & 68 deletions src/fmu/dataio/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import shutil
import uuid
from copy import deepcopy
from datetime import datetime
from pathlib import Path
from typing import Any, Final, Literal

Expand Down Expand Up @@ -441,70 +440,3 @@ def glue_metadata_preprocessed(
meta["tracklog"].extend(newmeta["tracklog"])

return meta


def parse_timedata(
datablock: dict,
isoformat: bool = True,
) -> tuple[str | None, str | None]:
"""The time section under datablock has variants to parse.
Formats::
"time": {
"t0": {
"value": "2022-08-02T00:00:00",
"label": "base"
}
}
# with or without t1
# or legacy format:
"time": [
{
"value": "2030-01-01T00:00:00",
"label": "moni"
},
{
"value": "2010-02-03T00:00:00",
"label": "base"
}
],
In addition, need to parse the dates on isoformat string format to YYYMMDD
Args:
datablock: The data block section from a metadata record
Returns
(t0, t1) where t0 is e.g. "20220907" as string objects and/or None if not
isoformat, while t0 is on form "2030-01-23T00:00:00" if isoformat is True
"""
date0 = None
date1 = None
if "time" not in datablock:
return (None, None)

if isinstance(datablock["time"], list):
date0 = datablock["time"][0]["value"]

if len(datablock["time"]) == 2:
date1 = datablock["time"][1]["value"]

elif isinstance(datablock["time"], dict):
date0 = datablock["time"]["t0"].get("value")
if "t1" in datablock["time"]:
date1 = datablock["time"]["t1"].get("value")

if not isoformat:
if date0:
tdate0 = datetime.strptime(date0, "%Y-%m-%dT%H:%M:%S")
date0 = tdate0.strftime("%Y%m%d")

if date1:
tdate1 = datetime.strptime(date1, "%Y-%m-%dT%H:%M:%S")
date1 = tdate1.strftime("%Y%m%d")

return (date0, date1)
12 changes: 10 additions & 2 deletions src/fmu/dataio/datastructure/meta/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import BaseModel, Field, GetJsonSchemaHandler, RootModel, model_validator
from pydantic import (
AwareDatetime,
BaseModel,
Field,
GetJsonSchemaHandler,
NaiveDatetime,
RootModel,
model_validator,
)
from pydantic_core import CoreSchema
from typing_extensions import Annotated

Expand All @@ -18,7 +26,7 @@ class FMUTimeObject(BaseModel):
default=None,
examples=["base", "monitor", "mylabel"],
)
value: Optional[str] = Field(
value: Optional[Union[NaiveDatetime, AwareDatetime]] = Field(
default=None,
examples=["2020-10-28T14:28:02"],
)
Expand Down
58 changes: 52 additions & 6 deletions src/fmu/dataio/providers/objectdata/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from fmu.dataio._definitions import ConfigurationError
from fmu.dataio._logging import null_logger
from fmu.dataio._utils import generate_description, parse_timedata
from fmu.dataio._utils import generate_description
from fmu.dataio.datastructure._internal.internal import AllowedContent
from fmu.dataio.datastructure.meta import content

Expand Down Expand Up @@ -65,6 +65,49 @@ def derive_name(
return ""


def get_timedata_from_existing(meta_timedata: dict) -> tuple[datetime, datetime | None]:
"""Converts the time data in existing metadata from a string to a datetime.
The time section under datablock has variants to parse.
Formats::
"time": {
"t0": {
"value": "2022-08-02T00:00:00",
"label": "base"
}
}
# with or without t1
# or legacy format:
"time": [
{
"value": "2030-01-01T00:00:00",
"label": "moni"
},
{
"value": "2010-02-03T00:00:00",
"label": "base"
}
],
"""
date1 = None
if isinstance(meta_timedata, list):
date0 = meta_timedata[0]["value"]
if len(meta_timedata) == 2:
date1 = meta_timedata[1]["value"]
elif isinstance(meta_timedata, dict):
date0 = meta_timedata["t0"].get("value")
if "t1" in meta_timedata:
date1 = meta_timedata["t1"].get("value")

return (
datetime.strptime(date0, "%Y-%m-%dT%H:%M:%S"),
datetime.strptime(date1, "%Y-%m-%dT%H:%M:%S") if date1 else None,
)


def get_fmu_time_object(timedata_item: list[str]) -> content.FMUTimeObject:
"""
Returns a FMUTimeObject from a timedata item on list
Expand All @@ -73,7 +116,7 @@ def get_fmu_time_object(timedata_item: list[str]) -> content.FMUTimeObject:
"""
value, *label = timedata_item
return content.FMUTimeObject(
value=datetime.strptime(str(value), "%Y%m%d").isoformat(),
value=datetime.strptime(str(value), "%Y%m%d"),
label=label[0] if label else None,
)

Expand Down Expand Up @@ -103,8 +146,8 @@ class ObjectDataProvider(ABC):
efolder: str = field(default="")
extension: str = field(default="")
fmt: str = field(default="")
time0: str | None = field(default=None)
time1: str | None = field(default=None)
time0: datetime | None = field(default=None)
time1: datetime | None = field(default=None)

@staticmethod
def _validate_get_ext(fmt: str, subtype: str, validator: dict[str, V]) -> V:
Expand Down Expand Up @@ -205,7 +248,7 @@ def _derive_timedata(self) -> dict[str, str] | None:
if stop:
assert start and start.value is not None # for mypy
assert stop and stop.value is not None # for mypy
if datetime.fromisoformat(start.value) > datetime.fromisoformat(stop.value):
if start.value > stop.value:
start, stop = stop, start

self.time0, self.time1 = start.value, stop.value if stop else None
Expand Down Expand Up @@ -294,7 +337,10 @@ def from_metadata_dict(
"""Instantiate from existing metadata."""

relpath = Path(meta_existing["file"]["relative_path"])
time0, time1 = parse_timedata(meta_existing["data"])

time0, time1 = None, None
if "time" in meta_existing["data"]:
time0, time1 = get_timedata_from_existing(meta_existing["data"]["time"])

return cls(
obj=obj,
Expand Down
28 changes: 28 additions & 0 deletions tests/test_units/test_objectdataprovider_class.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
"""Test the _ObjectData class from the _objectdata.py module"""

import os
from datetime import datetime

import pytest
from fmu.dataio import dataio
from fmu.dataio._definitions import ConfigurationError, ValidFormats
from fmu.dataio.providers.objectdata._base import (
get_timedata_from_existing,
)
from fmu.dataio.providers.objectdata._provider import (
objectdata_provider_factory,
)
from fmu.dataio.providers.objectdata._xtgeo import RegularSurfaceDataProvider

from ..utils import inside_rms


@pytest.mark.parametrize(
"given, expected",
(
(
{"t0": {"value": "2022-08-02T00:00:00", "label": "base"}},
(datetime.strptime("2022-08-02T00:00:00", "%Y-%m-%dT%H:%M:%S"), None),
),
(
[
{"value": "2030-01-01T00:00:00", "label": "moni"},
{"value": "2010-02-03T00:00:00", "label": "base"},
],
(
datetime.strptime("2030-01-01T00:00:00", "%Y-%m-%dT%H:%M:%S"),
datetime.strptime("2010-02-03T00:00:00", "%Y-%m-%dT%H:%M:%S"),
),
),
),
)
def test_get_timedata_from_existing(given: dict, expected: tuple):
assert get_timedata_from_existing(given) == expected


# --------------------------------------------------------------------------------------
# RegularSurface
# --------------------------------------------------------------------------------------
Expand Down
49 changes: 0 additions & 49 deletions tests/test_units/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,55 +34,6 @@ def test_check_if_number(value, result):
assert utils.check_if_number(value) == result


@pytest.mark.parametrize(
"given, expected, isoformat",
(
(
{},
(None, None),
True,
),
(
{"time": {"t0": {"value": "2022-08-02T00:00:00", "label": "base"}}},
("2022-08-02T00:00:00", None),
True,
),
(
{
"time": [
{"value": "2030-01-01T00:00:00", "label": "moni"},
{"value": "2010-02-03T00:00:00", "label": "base"},
]
},
("2030-01-01T00:00:00", "2010-02-03T00:00:00"),
True,
),
(
{},
(None, None),
False,
),
(
{"time": {"t0": {"value": "2022-08-02T00:00:00", "label": "base"}}},
("20220802", None),
False,
),
(
{
"time": [
{"value": "2030-01-01T00:00:00", "label": "moni"},
{"value": "2010-02-03T00:00:00", "label": "base"},
]
},
("20300101", "20100203"),
False,
),
),
)
def test_parse_timedata(given: dict, expected: tuple, isoformat: bool):
assert utils.parse_timedata(given, isoformat) == expected


def test_get_object_name():
assert utils.get_object_name(object()) is None

Expand Down

0 comments on commit d07f923

Please sign in to comment.