From 0756fc8af9f2845431b2b4e8d262d64060d2140a Mon Sep 17 00:00:00 2001 From: "a.krantz" Date: Tue, 8 Oct 2024 12:17:52 +0000 Subject: [PATCH] added from_pd_timestamp with tests --- src/odsbox/asam_time.py | 26 +++++++++++++++-- tests/test_asam_time.py | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/odsbox/asam_time.py b/src/odsbox/asam_time.py index 9c40013..981cadc 100644 --- a/src/odsbox/asam_time.py +++ b/src/odsbox/asam_time.py @@ -1,4 +1,4 @@ -"""datetime is represented as string in ASAM ODS. Here you find some helpers.""" +"""datetime is represented as string in ASAM ODS formatted using YYYYMMDDHHMMSSFFF. Here you find some helpers.""" from __future__ import annotations @@ -22,7 +22,8 @@ def to_pd_timestamp(asam_time: str) -> pd.Timestamp: """ Convert ASAM ODS datetime string to pandas Timestamp. - :param str asam_time: ASAM ODS datetime string to be converted + :param str asam_time: ASAM ODS datetime string to be converted. formatted like `YYYYMMDDHHMMSSFFF`. + It must at least contain `YYYYMMDD`. :raises requests.SyntaxError: If content is invalid. :return pd.Timestamp: Corresponding pandas Timestamp value. For empty string `pd.NaT` is returned. """ @@ -42,3 +43,24 @@ def to_pd_timestamp(asam_time: str) -> pd.Timestamp: microsecond=int(asam_time_normalized[14:20]) if asam_time_len >= 20 else 0, nanosecond=int(asam_time_normalized[20:23]) if asam_time_len >= 23 else 0, ) + + +def from_pd_timestamp(timestamp: pd.Timestamp, length: int = 17) -> str: + """ + Convert a pandas Timestamp to a string formatted as asamtime (`YYYYMMDDHHMMSSFFF`). + + :param pd.Timestamp timestamp: The pandas Timestamp to convert. The timezone + information given in timestamp is ignored. + :param int length: The desired length of the output string. The final string will + be truncated to the specified length. The maximum is 23 including + nanoseconds. + :return str: The asam time representation of the timestamp. For `None` or `pd.NaT` + an empty string is returned. + """ + if timestamp is None or pd.isna(timestamp): + return "" + + asam_time_str = timestamp.strftime("%Y%m%d%H%M%S%f") + if length > 20: + asam_time_str += f"{timestamp.nanosecond:03d}" + return asam_time_str[: min(length, len(asam_time_str))] diff --git a/tests/test_asam_time.py b/tests/test_asam_time.py index 5d47cd2..4bcdeb3 100644 --- a/tests/test_asam_time.py +++ b/tests/test_asam_time.py @@ -8,6 +8,68 @@ import pandas as pd +def test_from_pd_timestamp(): + dates = [ + ("20241211", "2024-12-11T00:00:00"), + ("20241211133310", "2024-12-11T13:33:10"), + ("2024121113331056", "2024-12-11T13:33:10.560000"), + ("20241211133310561234567", "2024-12-11T13:33:10.561234567"), + ("2024121113", "2024-12-11T13:00:00"), + ("202412111333", "2024-12-11T13:33:00"), + ("20241211133356", "2024-12-11T13:33:56"), + ("202412111333561", "2024-12-11T13:33:56.100000"), + ("2024121113335612", "2024-12-11T13:33:56.120000"), + ("20241211133356123", "2024-12-11T13:33:56.123000"), + ("202412111333561234", "2024-12-11T13:33:56.123400"), + ("2024121113335612345", "2024-12-11T13:33:56.123450"), + ("20241211133356123456", "2024-12-11T13:33:56.123456"), + ("202412111333561234567", "2024-12-11T13:33:56.123456700"), + ("2024121113335612345678", "2024-12-11T13:33:56.123456780"), + ("20241211133356123456789", "2024-12-11T13:33:56.123456789"), + ("20241211133356123456789", "2024-12-11T13:33:56.123456789"), + ("19700101", "1970-01-01T00:00:00"), + ("1970010100", "1970-01-01T00:00:00"), + ("197001010000", "1970-01-01T00:00:00"), + ("19700101000000", "1970-01-01T00:00:00"), + ] + + for date in dates: + pd_timestamp_in = pd.Timestamp(date[1]) + result = asam_time.from_pd_timestamp(pd_timestamp_in, length=len(date[0])) + assert result == date[0] + # lets do the roundtrip + pd_timestamp_out = asam_time.to_pd_timestamp(result) + assert pd_timestamp_out == pd_timestamp_in + + +def test_from_pd_timestamp_special(): + assert "20241211000000000000000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T00:00:00"), 23) + assert "20241211000000000000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T00:00:00"), 20) + assert "20241211000000000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T00:00:00"), 17) + assert "20241211000000000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T00:00:00")) + + +def test_from_pd_timestamp_z(): + assert "20241211133310000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:10Z")) + assert "20240711133310000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-07-11T13:33:10Z")) + assert "20241211133310000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:10+02")) + assert "20240711133310000" == asam_time.from_pd_timestamp(pd.Timestamp("2024-07-11T13:33:10+02")) + + +def test_from_pd_timestamp_special2(): + assert "20241211133356123456789" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789"), 23) + assert "20241211133356123" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789")) + assert "20241211133356123456789" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789"), 26) + assert "20241211133356123456" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789"), 20) + assert "20241211133356123" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789"), 17) + assert "20241211133356" == asam_time.from_pd_timestamp(pd.Timestamp("2024-12-11T13:33:56.123456789"), 14) + + +def test_from_pd_timestamp_none(): + assert "" == asam_time.from_pd_timestamp(pd.NaT) + assert "" == asam_time.from_pd_timestamp(None) + + def test_to_pd_timestamp(): dates = [ ("20241211", "2024-12-11T00:00:00"),