Skip to content

Commit af034dd

Browse files
miss-islingtonVlad4896blurb-it[bot]
authored
[3.12] gh-117534: Add checking for input parameter in iso_to_ymd (GH-117543) (#117689)
gh-117534: Add checking for input parameter in iso_to_ymd (GH-117543) Moves the validation for invalid years in the C implementation of the `datetime` module into a common location between `fromisoformat` and `fromisocalendar`, which improves the error message and fixes a failed assertion when parsing invalid ISO 8601 years using one of the "ISO weeks" formats. --------- (cherry picked from commit d5f1139) Co-authored-by: Vlad4896 <166005126+Vlad4896@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent 2683127 commit af034dd

File tree

4 files changed

+16
-7
lines changed

4 files changed

+16
-7
lines changed

Lib/test/datetimetester.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,10 @@ def test_fromisoformat_fails(self):
19081908
'2009-02-29', # Invalid leap day
19091909
'2019-W53-1', # No week 53 in 2019
19101910
'2020-W54-1', # No week 54
1911+
'0000-W25-1', # Invalid year
1912+
'10000-W25-1', # Invalid year
1913+
'2020-W25-0', # Invalid day-of-week
1914+
'2020-W25-8', # Invalid day-of-week
19111915
'2009\ud80002\ud80028', # Separators are surrogate codepoints
19121916
]
19131917

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ David Edelsohn
492492
John Edmonds
493493
Benjamin Edwards
494494
Grant Edwards
495+
Vlad Efanov
495496
Zvi Effron
496497
John Ehresman
497498
Tal Einat
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve validation logic in the C implementation of :meth:`datetime.fromisoformat`
2+
to better handle invalid years. Patch by Vlad Efanov.

Modules/_datetimemodule.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ iso_week1_monday(int year)
392392
static int
393393
iso_to_ymd(const int iso_year, const int iso_week, const int iso_day,
394394
int *year, int *month, int *day) {
395+
// Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5)
396+
if (iso_year < MINYEAR || iso_year > MAXYEAR) {
397+
return -4;
398+
}
395399
if (iso_week <= 0 || iso_week >= 53) {
396400
int out_of_range = 1;
397401
if (iso_week == 53) {
@@ -738,7 +742,7 @@ parse_isoformat_date(const char *dtstr, const size_t len, int *year, int *month,
738742
* -2: Inconsistent date separator usage
739743
* -3: Failed to parse ISO week.
740744
* -4: Failed to parse ISO day.
741-
* -5, -6: Failure in iso_to_ymd
745+
* -5, -6, -7: Failure in iso_to_ymd
742746
*/
743747
const char *p = dtstr;
744748
p = parse_digits(p, year, 4);
@@ -3097,15 +3101,13 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw)
30973101
return NULL;
30983102
}
30993103

3100-
// Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5)
3101-
if (year < MINYEAR || year > MAXYEAR) {
3102-
PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year);
3103-
return NULL;
3104-
}
3105-
31063104
int month;
31073105
int rv = iso_to_ymd(year, week, day, &year, &month, &day);
31083106

3107+
if (rv == -4) {
3108+
PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year);
3109+
return NULL;
3110+
}
31093111

31103112
if (rv == -2) {
31113113
PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);

0 commit comments

Comments
 (0)