Ambiguous years in `dd/mm/yy` format
- Dominant language
- Haskell
- Stars
- 4.3k
- Forks
- 740
- PR merge metrics
- No merged PRs in 30d
Description
One of the most common formats for dates is `dd/mm/yy` (and variants like `dd.mm.yy`) which sadly can introduce a lot of ambiguities. For example, consider the input `3/4/10`. Valid interpretations are:
- `dd/mm/yy`: April 3, 2010
- `mm/dd/yy`: March 4, 2010
But also, consider what happens with the year:
- `yy/mm/dd`: April 10, 2003
- `yy/dd/mm`: October 4, 2003
As you can see, a particular ambiguity is the `year`, mainly since we are accepting only 2 digits as valid years. Duckling then `converts 2-digits to a year between 1950 and 2050` through the `year` helper:
https://github.com/facebook/duckling/blob/dd70d80dc1c9b47a8b68ce36ba12c0da4e376d3e/Duckling/Time/Helpers.hs#L446-L450
*For example, the number `3` gets converted to the year `2003`, `20` to `2020` and `40` to `2040`*
The issue here is that we are ignoring perfectly valid interpretations of inputs like "1/1/40" as `January 1, 1940`. Currently, we only get `January 1, 2040` as the only answer. It's true that in practice, if we're dealing with 2 digit years we assume that the year must be close to the **reference time**.
Here the first issue: the current `year` helper converts 2 digits to years between 1950 and 2050 **independently of the reference time**. If we used `1/1/1821` as reference time, then dates like "1/1/25` would return `January 1, 2025`, when `January 1, 1825` is probably the desired answer.
---
My idea is to recreate the current months behavior but for years. If we say `April`, then Duckling returns a list of the next three Aprils, relative to the year of the reference time. For years, this would mean that if we say `20`, then Duckling would return a list of valid years, like `1920`, `2020` and `2120`. The main difference is that the resulting months are always "in the future", while years should also be considered to be in the past, at least one answer. We could, for example, take the last two years and the next one, so in case of `20` we return `1820`, `1920` and `2020` (with `2013` as reference year).
As a first instance, I would remove the conversion from the `year` predicate and leave the input number untouched. Then I would take a look into the `runYearPredicate` and try to mimic the `runMonthPredicate`:
https://github.com/facebook/duckling/blob/dd70d80dc1c9b47a8b68ce36ba12c0da4e376d3e/Duckling/Time/Types.hs#L555-L577
Sadly, I get stuck in this part since I don't really understand how Duckling runs predicates. I would appreciate any hints on how this could work, if it's feasible and also possible regressions that this change would introduce.
Contributor guide
Research direction
Start with Duckling/Time/Helpers.hs at the linked year helper and Duckling/Time/Types.hs around runYearPredicate and runMonthPredicate. Trace how predicates are executed and compare the year and month paths. Done means two-digit years use the reference time and return the intended past and future interpretations, with regressions checked against existing behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- haskell
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100