diff --git a/.github/workflows/install_and_test.yml b/.github/workflows/install_and_test.yml index eadbc8b67..4884b9493 100644 --- a/.github/workflows/install_and_test.yml +++ b/.github/workflows/install_and_test.yml @@ -33,6 +33,7 @@ jobs: python -m pip install --upgrade ./dist/*.whl python -m pip install pytest python -m pip install pyshacl + python -m pip install tzdata python -m pip install networkx shell: bash - name: Run tests diff --git a/pyproject.toml b/pyproject.toml index 19e1aa59a..aff57e36b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = ["click", "pyyaml", "xmltodict", "rdflib", "beartype", "uritools" dynamic = ["version"] [project.optional-dependencies] -test = ["pytest", "pyshacl"] +test = ["pytest", "pyshacl", "tzdata"] code_style = ["isort", "black", "flake8"] graph_generation = ["pygraphviz", "networkx"] development = ["black", "flake8", "isort", "networkx", "pytest"] diff --git a/src/spdx_tools/spdx/datetime_conversions.py b/src/spdx_tools/spdx/datetime_conversions.py index 7b54ae91e..cce624d57 100644 --- a/src/spdx_tools/spdx/datetime_conversions.py +++ b/src/spdx_tools/spdx/datetime_conversions.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2022 spdx contributors # # SPDX-License-Identifier: Apache-2.0 -from datetime import datetime +from datetime import datetime, timezone def datetime_from_str(date_str: str) -> datetime: @@ -16,6 +16,10 @@ def datetime_to_iso_string(date: datetime) -> str: """ Return an ISO-8601 representation of a datetime object. """ + if date.tzinfo is not None: + date = date.astimezone(timezone.utc) # Convert aware datetimes to UTC + date = date.replace(tzinfo=None) # Convert to naive datetime + if date.microsecond != 0: date = date.replace(microsecond=0) # SPDX does not support microseconds diff --git a/tests/spdx/test_datetime_conversions.py b/tests/spdx/test_datetime_conversions.py index 2c4858ced..3967d593b 100644 --- a/tests/spdx/test_datetime_conversions.py +++ b/tests/spdx/test_datetime_conversions.py @@ -1,12 +1,27 @@ # SPDX-FileCopyrightText: 2022 spdx contributors # # SPDX-License-Identifier: Apache-2.0 -from datetime import datetime +from datetime import datetime, timezone import pytest from spdx_tools.spdx.datetime_conversions import datetime_from_str, datetime_to_iso_string +# The following is required as long as we support Python 3.8.x or +# older. Once Python 3.9 is the oldest version we support, we can +# rely solely on the section which imports and uses zoneinfo. + +try: + # Python 3.9 and later + from zoneinfo import ZoneInfo + + tz_nyc = ZoneInfo("America/New_York") +except ImportError: + # Python 3.8 and earlier + from datetime import timedelta + + tz_nyc = timezone(timedelta(hours=-4)) + def test_datetime_to_iso_string(): assert datetime_to_iso_string(datetime(2022, 12, 13, 1, 2, 3)) == "2022-12-13T01:02:03Z" @@ -16,6 +31,16 @@ def test_datetime_to_iso_string_with_microseconds(): assert datetime_to_iso_string(datetime(2022, 12, 13, 1, 2, 3, 666666)) == "2022-12-13T01:02:03Z" +def test_utc_datetime_to_iso_string(): + dt = datetime(2023, 10, 4, 1, 2, 3, tzinfo=timezone.utc) + assert datetime_to_iso_string(dt) == "2023-10-04T01:02:03Z" + + +def test_local_datetime_to_iso_string(): + dt = datetime(2023, 10, 4, 1, 2, 3, tzinfo=tz_nyc) + assert datetime_to_iso_string(dt) == "2023-10-04T05:02:03Z" + + def test_datetime_from_str(): date_str = "2010-03-04T05:45:11Z"