Commit f9f97c3
committed
fix(dtypes): dayfirst=True no longer corrupts ISO-8601 dates
fd.clean(df, dayfirst=True) on ["2021-01-05", "2021-02-11"] silently
returned 2021-05-01 and 2021-11-02 -- month and day swapped, with no
warning, no report entry and no coercion record.
dayfirst exists to resolve ambiguous short dates like 05/12/2021. An
ISO-8601 date is YYYY-MM-DD by definition and has no ambiguity to resolve,
so this was not a defensible reading of the input.
Cause: pandas 2 infers one format for a whole column from its first value,
and under dayfirst=True reads an ISO date as %Y-%d-%m. _parse_datetime now
passes format="mixed" in that case, so each value is read by its own shape.
pandas 1.x infers per value and was never affected -- verified directly on
1.5.3 -- and has no format="mixed", hence the version guard.
What made it easy to miss is that the corruption was data-dependent. It was
silent only while every day was <= 12: a day >= 13 made the guessed format
fail on that value, dropped the parse share below datetime_threshold, and
triggered the mixed-format retry that produced the correct reading. The same
column therefore read correctly or incorrectly depending on values it
happened to contain, or on an unrelated threshold. A user validating on a
sample containing a day >= 13 would see correct output and ship.
Only the top-level dayfirst=True kwarg was affected. dayfirst="auto" and
both semantic_context routes were already correct, which is why this was
never caught.
Verified the tests fail without the fix rather than assuming: reverting src
gives 3 failed / 5 passed. With it, 8 pass on py3.12/pandas 2.3.3 and on
py3.9/pandas 1.5.3. dayfirst still resolves genuinely ambiguous slash dates
in both directions.1 parent e1520d7 commit f9f97c3
3 files changed
Lines changed: 119 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
9 | 37 | | |
10 | 38 | | |
11 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
381 | 381 | | |
382 | 382 | | |
383 | 383 | | |
384 | | - | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
385 | 394 | | |
386 | 395 | | |
387 | 396 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
0 commit comments