Skip to content

Commit 01b9b79

Browse files
committed
Support microsecond timestamp resolution
The dateTimeStamp XML standard type supports fractional second notation: https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp Before this patch, the tool crashed when fractional timestamps were given in e.g. CreationInfo. Current implementation is limited to microsecond resolution. More fine-grained timestamps (nanosecond), will be silently truncated to microsecond resolution. Signed-off-by: Zalan Blenessy <zalan.blenessy@volvocars.com>
1 parent 4c9e2a6 commit 01b9b79

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

src/spdx_tools/spdx/datetime_conversions.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
# SPDX-FileCopyrightText: 2022 spdx contributors
22
#
33
# SPDX-License-Identifier: Apache-2.0
4+
import re
45
from datetime import datetime, timezone
56

67

78
def datetime_from_str(date_str: str) -> datetime:
89
if not isinstance(date_str, str):
910
raise TypeError(f"Could not convert str to datetime, invalid type: {type(date_str).__name__}")
1011

11-
date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match
12-
return date
12+
if "." not in date_str:
13+
return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match
14+
15+
# Based on the https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp
16+
# The secondFrag allows fractional second notation as well.
17+
# normalize to micro seconds so that we can use %f with strptime
18+
date_str = re.sub(r"\.(\d{1,6})\d*Z$", r".\1Z", date_str)
19+
return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ") # raises ValueError if format does not match
1320

1421

1522
def datetime_to_iso_string(date: datetime) -> str:

tests/spdx/test_datetime_conversions.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,22 @@ def test_local_datetime_to_iso_string():
4343

4444
def test_datetime_from_str():
4545
date_str = "2010-03-04T05:45:11Z"
46+
assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11)
4647

47-
date = datetime_from_str(date_str)
48+
date_str = "2010-03-04T05:45:11.0Z"
49+
assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11)
4850

49-
assert date == datetime(2010, 3, 4, 5, 45, 11)
51+
# implicit notation
52+
date_str = "2010-03-04T05:45:11.1Z"
53+
assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11, 100000)
54+
55+
# explicity notation
56+
date_str = "2010-03-04T05:45:11.123456Z"
57+
assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11, 123456)
58+
59+
# truncation of nano seconds
60+
date_str = "2010-03-04T05:45:11.1234567Z"
61+
assert datetime_from_str(date_str) == datetime(2010, 3, 4, 5, 45, 11, 123456)
5062

5163

5264
@pytest.mark.parametrize(

tests/spdx3/writer/tag_value/test_write_document.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ def test_render_creation_info():
2929
output_str = io.StringIO()
3030
write_spdx_document(spdx_document, text_output=output_str)
3131

32-
assert (
33-
output_str.getvalue()
34-
== """\
32+
assert output_str.getvalue() == """\
3533
## SPDX Document
3634
SPDXID: SPDXRef-FOO
3735
name: BAR
@@ -42,4 +40,3 @@ def test_render_creation_info():
4240
data license: CC0-1.0
4341
elements:
4442
""" # noqa: W291 # elements: are printed with a space
45-
)

0 commit comments

Comments
 (0)