How to allow negative years (i.e. BCE years) with MUI X Date Pickers?

How to allow negative years (i.e. BCE years) with MUI X Date Pickers?

I was messing about with the minDate prop on the MUI X Date Picker (specifically the DatePicker component). I was trying to set the minDate to a date with a negative year (i.e. a BCE year) in order to allow picking those years with the date picker.

However, the problem with this is that if I do so, I appear to get errors like:

Warning: Encountered two children with the same key, `0001`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

I am using date-fns with mui-x.

Answer

It turns out that there are a few problems here.

The first is the assumption that the Gregorian Calendar even makes sense with BCE years. The Gregorian Calendar was introduced in 1582, and before that it may not make sense to use dates using the Gregorian Calendar depending on use case. However, provision is made for BCE years regardless; to quote wikipedia:

However, years before 1583 (the first full year following the introduction of the Read more) are not automatically allowed by the standard. Instead, the standard states that "values in the range [0000] through [1582] shall only be used by mutual agreement of the partners in information interchange".

To represent years before 0000 or after 9999, the standard also permits the expansion of the year representation but only by prior agreement between the sender and the receiver.[20] An expanded year representation [±YYYYY] must have an agreed-upon number of extra year digits beyond the four-digit minimum, and it must be prefixed with a + or − sign[21] instead of the more common AD/BC (or CE/BCE) notation; by convention 1 BC is labelled +0000, 2 BC is labeled −0001, and so on.[22]

https://en.wikipedia.org/wiki/ISO_8601#Years

Secondly, assuming we are okay with that, and we still want to proceed with allowing BCE, pre-1582 gregorian calendar dates to be selectable with the date picker, it turns out this problem isn't a problem with mui-x itself, but rather the date library being used. If you try to do this with moment or luxon, you will find that the problem does not present itself. Meanwhile, dayjs does not emit an error either, but you do get a somewhat strange looking year with the year 2 BCE that I honestly thought was a bug at first (00-1). This is a problem that only happens when using date-fns .

It turns out with date-fns the default formatting string that mui-x uses with date-fns is yyyy , which causes BCE years to be formatted as their absolute value in BCE instead (e.g. the ISO 8601 year 0000 which represents 1 BCE will be formatted to 0001, -0001 becomes 0002 etc). It seems that mui-x simply uses the value of the formatted year as the React key for each of the year pickers in the list of years, which means that when you have BCE years and CE years in that list, you will end up with children with the same key.

One simple way to solve this is to simply change the format string that mui-x uses for date-fns to uuuu, which will format years as the ISO 8601 suggests, with 1 BCE as 0000 , 2 BCE as -0001 , 3 BCE as -0002 etc. (You can argue that all the positive years should become +0000 , +0001 etc, but take that up with the date-fns people!).

e.g. using LocalizationProvider

<LocalizationProvider
  dateAdapter={AdapterDateFns}
  dateFormats={{ year: 'uuuu' }}
>
  <DatePicker minDate={someTimeInBCE} />
</LocalizationProvider>

I have also set up a sandbox to show how this works with each of the date libraries: https://stackblitz.com/edit/react-fn2xa3yy?file=Demo.tsx

The dayjs date format does look a little strange but I guess it's possible to get used to?

References:

Enjoyed this article?

Check out more content on our blog or follow us on social media.

Browse more articles