diff --git a/CHANGES.txt b/CHANGES.txt index 8651319d3..cf926d1e9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -8,6 +8,10 @@ Note that build 228 was the last version supporting Python 2. Since build 300: ---------------- +* Fixed a bug where certain COM dates would fail to be converted to a Python + datetime object with `ValueError: microsecond must be in 0..999999`. Shoutout + to @hujiaxing for reporting and helping reproduce the issue (#1655) + * Added win32com.shell.SHGetKnownFolderPath() and related constants. * Shifted work in win32.lib.pywin32_bootstrap to Python's import system from diff --git a/com/win32com/test/testPyComTest.py b/com/win32com/test/testPyComTest.py index f8394c1bc..6723ebd87 100644 --- a/com/win32com/test/testPyComTest.py +++ b/com/win32com/test/testPyComTest.py @@ -273,6 +273,9 @@ def TestCommon(o, is_generated): later = now + datetime.timedelta(seconds=1) TestApplyResult(o.EarliestDate, (now, later), now) + # The below used to fail with `ValueError: microsecond must be in 0..999999` - see #1655 + o.MakeDate(18712.308206013888) + progress("Checking currency") # currency. pythoncom.__future_currency__ = 1 diff --git a/win32/src/PyTime.cpp b/win32/src/PyTime.cpp index 335152382..eb63fb286 100644 --- a/win32/src/PyTime.cpp +++ b/win32/src/PyTime.cpp @@ -380,11 +380,16 @@ PyObject *PyWin_NewTime(PyObject *timeOb) double minutes = (hours - (int)hours) * 60.0; double seconds = round((minutes - (int)minutes) * 60.0, 4); double milliseconds = round((seconds - (int)seconds) * 1000.0, 0); - // assert(milliseconds>=0.0 && milliseconds<=999.0); - // Strip off the msec part of time double TimeWithoutMsecs = t - (ONETHOUSANDMILLISECONDS / 1000.0 * milliseconds); + // We might have rounded ms to 1000 which blows up datetime. Round up + // to the next second. + if (milliseconds >= 1000) { + TimeWithoutMsecs += 1.0; + milliseconds = 0; + } + // Let the OS translate the variant date/time SYSTEMTIME st; if (!VariantTimeToSystemTime(TimeWithoutMsecs, &st)) {