Skip to content

Commit 47649ab

Browse files
committed
Closes #27710: Disallow fold not in [0, 1] in time and datetime constructors.
1 parent 95e0df8 commit 47649ab

3 files changed

Lines changed: 36 additions & 11 deletions

File tree

Lib/datetime.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def _check_date_fields(year, month, day):
288288
raise ValueError('day must be in 1..%d' % dim, day)
289289
return year, month, day
290290

291-
def _check_time_fields(hour, minute, second, microsecond):
291+
def _check_time_fields(hour, minute, second, microsecond, fold):
292292
hour = _check_int_field(hour)
293293
minute = _check_int_field(minute)
294294
second = _check_int_field(second)
@@ -301,7 +301,9 @@ def _check_time_fields(hour, minute, second, microsecond):
301301
raise ValueError('second must be in 0..59', second)
302302
if not 0 <= microsecond <= 999999:
303303
raise ValueError('microsecond must be in 0..999999', microsecond)
304-
return hour, minute, second, microsecond
304+
if fold not in (0, 1):
305+
raise ValueError('fold must be either 0 or 1', fold)
306+
return hour, minute, second, microsecond, fold
305307

306308
def _check_tzinfo_arg(tz):
307309
if tz is not None and not isinstance(tz, tzinfo):
@@ -1059,8 +1061,8 @@ def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold
10591061
self.__setstate(hour, minute or None)
10601062
self._hashcode = -1
10611063
return self
1062-
hour, minute, second, microsecond = _check_time_fields(
1063-
hour, minute, second, microsecond)
1064+
hour, minute, second, microsecond, fold = _check_time_fields(
1065+
hour, minute, second, microsecond, fold)
10641066
_check_tzinfo_arg(tzinfo)
10651067
self = object.__new__(cls)
10661068
self._hour = hour
@@ -1369,8 +1371,8 @@ def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
13691371
self._hashcode = -1
13701372
return self
13711373
year, month, day = _check_date_fields(year, month, day)
1372-
hour, minute, second, microsecond = _check_time_fields(
1373-
hour, minute, second, microsecond)
1374+
hour, minute, second, microsecond, fold = _check_time_fields(
1375+
hour, minute, second, microsecond, fold)
13741376
_check_tzinfo_arg(tzinfo)
13751377
self = object.__new__(cls)
13761378
self._year = year

Lib/test/datetimetester.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,11 @@ def test_bad_constructor_arguments(self):
17241724
self.assertRaises(ValueError, self.theclass,
17251725
2000, 1, 31, 23, 59, 59,
17261726
1000000)
1727+
# bad fold
1728+
self.assertRaises(ValueError, self.theclass,
1729+
2000, 1, 31, fold=-1)
1730+
self.assertRaises(ValueError, self.theclass,
1731+
2000, 1, 31, fold=2)
17271732
# Positional fold:
17281733
self.assertRaises(TypeError, self.theclass,
17291734
2000, 1, 31, 23, 59, 59, 0, None, 1)

Modules/_datetimemodule.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ check_date_args(int year, int month, int day)
427427
* aren't, raise ValueError and return -1.
428428
*/
429429
static int
430-
check_time_args(int h, int m, int s, int us)
430+
check_time_args(int h, int m, int s, int us, int fold)
431431
{
432432
if (h < 0 || h > 23) {
433433
PyErr_SetString(PyExc_ValueError,
@@ -449,6 +449,11 @@ check_time_args(int h, int m, int s, int us)
449449
"microsecond must be in 0..999999");
450450
return -1;
451451
}
452+
if (fold != 0 && fold != 1) {
453+
PyErr_SetString(PyExc_ValueError,
454+
"fold must be either 0 or 1");
455+
return -1;
456+
}
452457
return 0;
453458
}
454459

@@ -3598,7 +3603,7 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
35983603
if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
35993604
&hour, &minute, &second, &usecond,
36003605
&tzinfo, &fold)) {
3601-
if (check_time_args(hour, minute, second, usecond) < 0)
3606+
if (check_time_args(hour, minute, second, usecond, fold) < 0)
36023607
return NULL;
36033608
if (check_tzinfo_subclass(tzinfo) < 0)
36043609
return NULL;
@@ -3926,8 +3931,14 @@ time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
39263931
if (tuple == NULL)
39273932
return NULL;
39283933
clone = time_new(Py_TYPE(self), tuple, NULL);
3929-
if (clone != NULL)
3934+
if (clone != NULL) {
3935+
if (fold != 0 && fold != 1) {
3936+
PyErr_SetString(PyExc_ValueError,
3937+
"fold must be either 0 or 1");
3938+
return NULL;
3939+
}
39303940
TIME_SET_FOLD(clone, fold);
3941+
}
39313942
Py_DECREF(tuple);
39323943
return clone;
39333944
}
@@ -4175,7 +4186,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
41754186
&second, &usecond, &tzinfo, &fold)) {
41764187
if (check_date_args(year, month, day) < 0)
41774188
return NULL;
4178-
if (check_time_args(hour, minute, second, usecond) < 0)
4189+
if (check_time_args(hour, minute, second, usecond, fold) < 0)
41794190
return NULL;
41804191
if (check_tzinfo_subclass(tzinfo) < 0)
41814192
return NULL;
@@ -5006,8 +5017,15 @@ datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
50065017
if (tuple == NULL)
50075018
return NULL;
50085019
clone = datetime_new(Py_TYPE(self), tuple, NULL);
5009-
if (clone != NULL)
5020+
5021+
if (clone != NULL) {
5022+
if (fold != 0 && fold != 1) {
5023+
PyErr_SetString(PyExc_ValueError,
5024+
"fold must be either 0 or 1");
5025+
return NULL;
5026+
}
50105027
DATE_SET_FOLD(clone, fold);
5028+
}
50115029
Py_DECREF(tuple);
50125030
return clone;
50135031
}

0 commit comments

Comments
 (0)