From 86c6d25f535ce03a89a8c46f690b834577db45e5 Mon Sep 17 00:00:00 2001 From: Nis Martensen Date: Tue, 2 Mar 2021 21:18:45 +0100 Subject: [PATCH 1/2] write ISO 8601 time strings with millisecond precision --HG-- branch : 3.0 --- openpyxl/cell/_writer.py | 4 ++-- openpyxl/utils/datetime.py | 4 +++- openpyxl/utils/tests/test_datetime.py | 12 ++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/openpyxl/cell/_writer.py b/openpyxl/cell/_writer.py index 32f753f9..fe496d84 100644 --- a/openpyxl/cell/_writer.py +++ b/openpyxl/cell/_writer.py @@ -3,7 +3,7 @@ from openpyxl.compat import safe_string from openpyxl.xml.functions import Element, SubElement, whitespace, XML_NS, REL_NS from openpyxl import LXML -from openpyxl.utils.datetime import to_excel, days_to_time +from openpyxl.utils.datetime import to_excel, days_to_time, to_ISO8601 from datetime import timedelta @@ -25,7 +25,7 @@ def _set_attributes(cell, styled=None): if cell.data_type == "d": if cell.parent.parent.iso_dates and not isinstance(value, timedelta): - value = value.isoformat() + value = to_ISO8601(value) else: attrs['t'] = "n" value = to_excel(value, cell.parent.parent.epoch) diff --git a/openpyxl/utils/datetime.py b/openpyxl/utils/datetime.py index 0b03a984..81f8ca9d 100644 --- a/openpyxl/utils/datetime.py +++ b/openpyxl/utils/datetime.py @@ -29,7 +29,9 @@ ISO_REGEX = re.compile(r''' def to_ISO8601(dt): """Convert from a datetime to a timestamp string.""" - return datetime.datetime.strftime(dt, ISO_FORMAT) + if hasattr(dt, "microsecond") and dt.microsecond: + return dt.isoformat(timespec="milliseconds") + return dt.isoformat() def from_ISO8601(formatted_string): diff --git a/openpyxl/utils/tests/test_datetime.py b/openpyxl/utils/tests/test_datetime.py index 8aba0bf7..88fa34b9 100644 --- a/openpyxl/utils/tests/test_datetime.py +++ b/openpyxl/utils/tests/test_datetime.py @@ -12,9 +12,17 @@ from datetime import ( import pytest -def test_to_iso(): +@pytest.mark.parametrize("value, expected", + [ + (datetime(2013, 7, 15, 6, 52, 33), "2013-07-15T06:52:33"), + (datetime(2013, 7, 15, 6, 52, 33, 123456), "2013-07-15T06:52:33.123"), + (date(2013, 7, 15), "2013-07-15"), + (time(0, 1, 42), "00:01:42"), + ] + ) +def test_to_iso(value, expected): from ..datetime import to_ISO8601 - assert to_ISO8601(datetime(2013, 7, 15, 6, 52, 33)) == "2013-07-15T06:52:33Z" + assert to_ISO8601(value) == expected @pytest.mark.parametrize("value, group, expected", -- GitLab From 9f698f68f2b377782cf479baaacf8341235c0a70 Mon Sep 17 00:00:00 2001 From: Nis Martensen Date: Tue, 2 Mar 2021 21:35:42 +0100 Subject: [PATCH 2/2] append 'Z' to some datetime iso strings --HG-- branch : 3.0 --- openpyxl/packaging/core.py | 7 +------ openpyxl/packaging/tests/test_core.py | 4 ++-- openpyxl/utils/tests/test_datetime.py | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/openpyxl/packaging/core.py b/openpyxl/packaging/core.py index d8320b6f..24593f4b 100644 --- a/openpyxl/packaging/core.py +++ b/openpyxl/packaging/core.py @@ -3,11 +3,6 @@ import datetime from openpyxl.compat import safe_string -from openpyxl.utils.datetime import ( - CALENDAR_WINDOWS_1900, - to_ISO8601, - from_ISO8601, -) from openpyxl.descriptors import ( String, DateTime, @@ -34,7 +29,7 @@ class NestedDateTime(DateTime, NestedText): tagname = "{%s}%s" % (namespace, tagname) el = Element(tagname) if value is not None: - el.text = to_ISO8601(value) + el.text = value.isoformat(timespec="seconds") + 'Z' return el diff --git a/openpyxl/packaging/tests/test_core.py b/openpyxl/packaging/tests/test_core.py index c57973ed..85fcb982 100644 --- a/openpyxl/packaging/tests/test_core.py +++ b/openpyxl/packaging/tests/test_core.py @@ -78,7 +78,7 @@ def test_from_tree(datadir, SampleProperties): def test_qualified_datetime(): from ..core import QualifiedDateTime dt = QualifiedDateTime() - tree = dt.to_tree("time", datetime.datetime(2015, 7, 20, 12, 30)) + tree = dt.to_tree("time", datetime.datetime(2015, 7, 20, 12, 30, 00, 123456)) xml = tostring(tree) expected = """