diff -r 760f222103c7 Lib/datetime.py --- a/Lib/datetime.py Mon Mar 02 09:36:48 2015 -0500 +++ b/Lib/datetime.py Tue Mar 03 16:38:28 2015 +0100 @@ -283,8 +283,8 @@ def _check_time_fields(hour, minute, sec raise ValueError('hour must be in 0..23', hour) if not 0 <= minute <= 59: raise ValueError('minute must be in 0..59', minute) - if not 0 <= second <= 59: - raise ValueError('second must be in 0..59', second) + if not 0 <= second <= 60: + raise ValueError('second must be in 0..60', second) if not 0 <= microsecond <= 999999: raise ValueError('microsecond must be in 0..999999', microsecond) return hour, minute, second, microsecond @@ -1385,7 +1385,6 @@ class datetime(date): t += 1 us = 0 y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) - ss = min(ss, 59) # clamp out leap seconds if the platform has them result = cls(y, m, d, hh, mm, ss, us, tz) if tz is not None: result = tz.fromutc(result) diff -r 760f222103c7 Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py Mon Mar 02 09:36:48 2015 -0500 +++ b/Lib/test/datetimetester.py Tue Mar 03 16:38:28 2015 +0100 @@ -1620,12 +1620,12 @@ class TestDateTime(TestDate): self.theclass(2000, 1, 31, 23, 0) # no exception self.theclass(2000, 1, 31, 23, 59) # no exception self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, -1) - self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 60) + self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 61) # bad seconds self.theclass(2000, 1, 31, 23, 59, 0) # no exception self.theclass(2000, 1, 31, 23, 59, 59) # no exception self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1) - self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60) + self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 61) # bad microseconds self.theclass(2000, 1, 31, 23, 59, 59, 0) # no exception self.theclass(2000, 1, 31, 23, 59, 59, 999999) # no exception @@ -2094,6 +2094,18 @@ class TestDateTime(TestDate): self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month + dt1.second - 7) + def test_leap_second(self): + # Issue #23574: test leap seconds + dt = self.theclass(2012, 6, 30, 23, 59, 60) + self.assertEqual(dt.second, 60) + + t = dt.timestamp() + dt2 = self.theclass.fromtimestamp(t) + self.assertEqual(dt, dt2) + + self.assertRaises(ValueError, self.theclass, 2012, 6, 30, 23, 59, 61) + + class TestSubclassDateTime(TestDateTime): theclass = SubclassDatetime # Override tests not designed for subclass @@ -2192,12 +2204,12 @@ class TestTime(HarmlessMixedComparison, self.theclass(23, 0) # no exception self.theclass(23, 59) # no exception self.assertRaises(ValueError, self.theclass, 23, -1) - self.assertRaises(ValueError, self.theclass, 23, 60) + self.assertRaises(ValueError, self.theclass, 23, 61) # bad seconds self.theclass(23, 59, 0) # no exception self.theclass(23, 59, 59) # no exception self.assertRaises(ValueError, self.theclass, 23, 59, -1) - self.assertRaises(ValueError, self.theclass, 23, 59, 60) + self.assertRaises(ValueError, self.theclass, 23, 59, 61) # bad microseconds self.theclass(23, 59, 59, 0) # no exception self.theclass(23, 59, 59, 999999) # no exception diff -r 760f222103c7 Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Mon Mar 02 09:36:48 2015 -0500 +++ b/Modules/_datetimemodule.c Tue Mar 03 16:38:28 2015 +0100 @@ -423,9 +423,9 @@ check_time_args(int h, int m, int s, int "minute must be in 0..59"); return -1; } - if (s < 0 || s > 59) { + if (s < 0 || s > 60) { PyErr_SetString(PyExc_ValueError, - "second must be in 0..59"); + "second must be in 0..60"); return -1; } if (us < 0 || us > 999999) { @@ -4058,14 +4058,6 @@ datetime_from_timet_and_us(PyObject *cls return PyErr_SetFromErrno(PyExc_OSError); } - /* The platform localtime/gmtime may insert leap seconds, - * indicated by tm->tm_sec > 59. We don't care about them, - * except to the extent that passing them on to the datetime - * constructor would raise ValueError for a reason that - * made no sense to the user. - */ - if (tm->tm_sec > 59) - tm->tm_sec = 59; return PyObject_CallFunction(cls, "iiiiiiiO", tm->tm_year + 1900, tm->tm_mon + 1,