diff --git a/src/spdx_tools/spdx/datetime_conversions.py b/src/spdx_tools/spdx/datetime_conversions.py index cce624d57..6f84c2cda 100644 --- a/src/spdx_tools/spdx/datetime_conversions.py +++ b/src/spdx_tools/spdx/datetime_conversions.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2022 spdx contributors # # SPDX-License-Identifier: Apache-2.0 +import re +import warnings from datetime import datetime, timezone @@ -8,8 +10,19 @@ def datetime_from_str(date_str: str) -> datetime: if not isinstance(date_str, str): raise TypeError(f"Could not convert str to datetime, invalid type: {type(date_str).__name__}") - date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match - return date + if "." not in date_str: + return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match + + # Based on the https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp + # The secondFrag allows fractional second notation as well. + # truncate the microsecond part + date_str = re.sub(r"\.\d*Z$", "Z", date_str) + warnings.warn( + "Invalid date format. Expected YYYY-MM-DDThh:mm:ssZ. Sub-second fractions have been discarded.", + category=UserWarning, + stacklevel=2, + ) + return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match def datetime_to_iso_string(date: datetime) -> str: diff --git a/tests/spdx/test_datetime_conversions.py b/tests/spdx/test_datetime_conversions.py index 3967d593b..068a13769 100644 --- a/tests/spdx/test_datetime_conversions.py +++ b/tests/spdx/test_datetime_conversions.py @@ -43,10 +43,13 @@ def test_local_datetime_to_iso_string(): def test_datetime_from_str(): date_str = "2010-03-04T05:45:11Z" + assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11) - date = datetime_from_str(date_str) + date_str = "2010-03-04T05:45:11.0Z" + assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11) - assert date == datetime(2010, 3, 4, 5, 45, 11) + date_str = "2010-03-04T05:45:11.123456789Z" + assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11) @pytest.mark.parametrize( diff --git a/tests/spdx3/writer/tag_value/test_write_document.py b/tests/spdx3/writer/tag_value/test_write_document.py index 580c61b81..10d5d54c6 100644 --- a/tests/spdx3/writer/tag_value/test_write_document.py +++ b/tests/spdx3/writer/tag_value/test_write_document.py @@ -29,9 +29,7 @@ def test_render_creation_info(): output_str = io.StringIO() write_spdx_document(spdx_document, text_output=output_str) - assert ( - output_str.getvalue() - == """\ + assert output_str.getvalue() == """\ ## SPDX Document SPDXID: SPDXRef-FOO name: BAR @@ -42,4 +40,3 @@ def test_render_creation_info(): data license: CC0-1.0 elements: """ # noqa: W291 # elements: are printed with a space - )