[Python-checkins] [3.6] bpo-29097: Forego fold detection on windows for low timestamp values (GH-2385) (GH-8498)
Alexander Belopolsky
webhook-mailer at python.org
Fri Jul 27 10:59:35 EDT 2018
https://github.com/python/cpython/commit/6ea8a3a0ebf840ca57b6dba9cad26fbb0ddaa5d4
commit: 6ea8a3a0ebf840ca57b6dba9cad26fbb0ddaa5d4
branch: 3.6
author: Ammar Askar <ammar_askar at hotmail.com>
committer: Alexander Belopolsky <abalkin at users.noreply.github.com>
date: 2018-07-27T10:59:27-04:00
summary:
[3.6] bpo-29097: Forego fold detection on windows for low timestamp values (GH-2385) (GH-8498)
On Windows, passing a negative value to local results in an OSError because localtime_s on Windows does not support negative timestamps. Unfortunately this means that fold detection for timestamps between 0 and max_fold_seconds will result in this OSError since we subtract max_fold_seconds from the timestamp to detect a fold. However, since we know there haven't been any folds in the interval [0, max_fold_seconds) in any timezone, we can hackily just forego fold detection for this time range on Windows..
(cherry picked from commit 96d1e69a12ed8ab80203277e1abdaf573457a964)
Co-authored-by: Ammar Askar <ammar_askar at hotmail.com>
files:
A Misc/NEWS.d/next/Windows/2018-05-16-11-31-17.bpo-29097.9mqEuI.rst
M Lib/datetime.py
M Lib/test/datetimetester.py
M Modules/_datetimemodule.c
diff --git a/Lib/datetime.py b/Lib/datetime.py
index b2b1457e376f..b8782fc8b363 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -6,6 +6,7 @@
import time as _time
import math as _math
+import sys
def _cmp(x, y):
return 0 if x == y else 1 if x > y else -1
@@ -1444,6 +1445,14 @@ def _fromtimestamp(cls, t, utc, tz):
# 23 hours at 1969-09-30 13:00:00 in Kwajalein.
# Let's probe 24 hours in the past to detect a transition:
max_fold_seconds = 24 * 3600
+
+ # On Windows localtime_s throws an OSError for negative values,
+ # thus we can't perform fold detection for values of time less
+ # than the max time fold. See comments in _datetimemodule's
+ # version of this method for more details.
+ if t < max_fold_seconds and sys.platform.startswith("win"):
+ return result
+
y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
probe1 = cls(y, m, d, hh, mm, ss, us, tz)
trans = result - probe1 - timedelta(0, max_fold_seconds)
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index d3fa7530edd4..40a457c9c538 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -69,7 +69,7 @@ def test_name_cleanup(self):
if not name.startswith('__') and not name.endswith('__'))
allowed = set(['MAXYEAR', 'MINYEAR', 'date', 'datetime',
'datetime_CAPI', 'time', 'timedelta', 'timezone',
- 'tzinfo'])
+ 'tzinfo', 'sys'])
self.assertEqual(names - allowed, set([]))
def test_divide_and_round(self):
@@ -4423,6 +4423,10 @@ def test_fromtimestamp_lord_howe(self):
self.assertEqual(t0.fold, 0)
self.assertEqual(t1.fold, 1)
+ def test_fromtimestamp_low_fold_detection(self):
+ # Ensure that fold detection doesn't cause an
+ # OSError for really low values, see bpo-29097
+ self.assertEqual(datetime.fromtimestamp(0).fold, 0)
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
def test_timestamp(self):
diff --git a/Misc/NEWS.d/next/Windows/2018-05-16-11-31-17.bpo-29097.9mqEuI.rst b/Misc/NEWS.d/next/Windows/2018-05-16-11-31-17.bpo-29097.9mqEuI.rst
new file mode 100644
index 000000000000..a59efc737f53
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2018-05-16-11-31-17.bpo-29097.9mqEuI.rst
@@ -0,0 +1,3 @@
+Fix bug where :meth:`datetime.fromtimestamp` erronously throws an
+:exc:`OSError` on Windows for values between 0 and 86400.
+Patch by Ammar Askar.
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index 148bd80190e8..64928b1f81c1 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -4309,7 +4309,22 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
second = Py_MIN(59, tm.tm_sec);
/* local timezone requires to compute fold */
- if (tzinfo == Py_None && f == _PyTime_localtime) {
+ if (tzinfo == Py_None && f == _PyTime_localtime
+ /* On Windows, passing a negative value to local results
+ * in an OSError because localtime_s on Windows does
+ * not support negative timestamps. Unfortunately this
+ * means that fold detection for time values between
+ * 0 and max_fold_seconds will result in an identical
+ * error since we subtract max_fold_seconds to detect a
+ * fold. However, since we know there haven't been any
+ * folds in the interval [0, max_fold_seconds) in any
+ * timezone, we can hackily just forego fold detection
+ * for this time range.
+ */
+#ifdef MS_WINDOWS
+ && (timet - max_fold_seconds > 0)
+#endif
+ ) {
long long probe_seconds, result_seconds, transition;
result_seconds = utc_to_seconds(year, month, day,
More information about the Python-checkins
mailing list