dmtrKovalenko / date-io

Abstraction over common javascript date management libraries
MIT License
723 stars 91 forks source link

Why does v2 hardcode the formats to English-specific formats? #250

Closed vdh closed 4 years ago

vdh commented 4 years ago

Changing over to that DateIOFormats hardcoded formats ignores all the important locale-specific formatting strings, like P/ PP / p etc for date-fns. It's not very useful trying to use i18n if all the format strings aren't leveraging the locale-specific formats.

dmtrKovalenko commented 4 years ago

The main problem is that is so hard to predict how the value will be displayed. For example https://codesandbox.io/s/heuristic-saha-ej6z6 - why the ru locale uses . as a delimiter? I agree that these formats

 fullDateTime12h: "yyyy, MMM do hh:mm aaa",
  fullDateTime24h: "yyyy, MMM do HH:mm",
  keyboardDate: "yyyy/MM/dd",
  keyboardDateTime12h: "yyyy/MM/dd hh:mm aaa",
  keyboardDateTime24h: "yyyy/MM/dd HH:mm"

Are pain in the ass. But for example in material-ui-pickers we are going to provide built-in localization for the formats. This will make possible to leverage the localized formats also for moment and dayjs where is no built-in localization.

But still you will be able to provide your own formats like

new DateFnsAdapter({ formats: { keyboardDate: 'P' }})

But I don't know how you will provide input mask for that format. Maybe @kossnocorp can help with that?

dmtrKovalenko commented 4 years ago

Maybe you have any better idea? I do think maybe we need to provide different sets of formats? For example

static localizedFormats = { ...defaultForamts, keyboardDate: 'P' } 

And then

const adapter = new DateFnsAdapter({ formats: DateFnsAdapter.localizedFormats }) 
kossnocorp commented 4 years ago

why the ru locale uses . as a delimiter?

Because that's the standard. The whole point of p tokens is to provide format that is common in the used territory. See as the reference: https://www.unicode.org/cldr/charts/32/summary/ru.html#2022

But I don't know how you will provide input mask for that format. Maybe @kossnocorp can help with that?

Sorry, I'm out of context, what is the problem and what exactly you mean by the input mask.

dmtrKovalenko commented 4 years ago

@kossnocorp the main problem this lib is solving - abstraction over the date-management libs, useful for date/time control oss projects. The giant problem is that we don't know which format will be used exactly to create an input mask for entering the date (ref: https://material-ui-pickers.dev/demo/datepicker#keyboard-input).

I don't think that there is some way to avoid hardcoded format tokens for keyboard-friendly input

kossnocorp commented 4 years ago

I see. Unfortunately, we don't expose these patterns even if you would like to convert it to a regexp or something that would allow you to build the mask.

However, parse allows parsing with P tokens (except the ones that include timezone), so that might be helpful.

dmtrKovalenko commented 4 years ago

@kossnocorp thanks :)

vdh commented 4 years ago

@dmtrKovalenko I don't really follow what you mean by Moment "where is no built-in localization.". Moment has a "Localized formats" section in their format docs.

Abstracting a layer over the top of date libraries is hampered if it ships with limits that greatly hobble the i18n functionality of the libraries. Please consider using the locale-specific formats for each library.

I solved the mask issue by formatting a dummy date and then replacing digits with "_". Something similar could be built in to solve this.

import format from "date-fns/format";
import { Locale } from "date-fns";

const digitRegex = /\d/g;

export default function keyboardDatePickerMask(locale: Locale, formatStr = "P") {
    return format(
        new Date(2020, 1, 1),
        formatStr,
        { locale },
    ).replace(digitRegex, "_");
}
dmtrKovalenko commented 4 years ago

Your solution is nice 👍 But it will not work with (1/2) digits. For example we can use ‘d’ localization token.

It allowed to enter 1 or 12.

dmtrKovalenko commented 4 years ago

Another idea: We can add some option like useLocalizedFormats in v2 that should disable input masking but accept localized inputs. (Another problem how to point users which specific format to use, but it is much easier than what we have right now)

Personally I prefer providing localized formats with mui localization feature, that will give us more control and ship better experience. But disabling mask could be an option for super international projects🤔

What do you think @oliviertassinari

oliviertassinari commented 4 years ago

@dmtrKovalenko They are a couple of unknown to me. It's the first time I really dive into this problem. Some thoughts:

  1. The keys exposed here feels somewhat arbitrary and tailored for the needs of @material-ui/pickers. Can they be used in a broader context? Do we have an example of people using it outside Material-UI? Collecting feedback from them would help! https://github.com/dmtrKovalenko/date-io/blob/a46f6fa30b6bc8d1115a19a1ebc24955785c3654/packages/date-fns/src/date-fns-utils.ts#L36-L57
  2. We are solving a two-dimensional problem. We aim to support x locales with y date libraries. In practice, both of these space tends to concentrate around a few actors (moment, english, chinese, date-fns, etc), with a long tail (french, etc).
  3. I think that we need to take a step back, and see how the whole system would work, integrated.
  4. If the date libraries have support for locale-aware formatting tokens, it will be significantly better to use them. So we can defer and concentrate the solution to these libraries, away from our localization strings. What date-fns does look great: https://runkit.com/oliviertassinari/5e1c83ce91dc5b001b64085d.
  5. It's interesting to see how Kendo-UI solves this problem, they feed in the data from CLDR directly: https://www.telerik.com/kendo-react-ui/components/dateinputs/datepicker/.
  6. We will likely need a solution for the Calendar component and the DataGrid (to format/edit the dates inside it)

The giant problem is that we don't know which format will be used exactly to create an input mask for entering the date

  1. What about we reconsider this tradeoff? What's the use case for the mask? I have looked at these projects to see how they solve the keyboard issue, on desktop, and grouped the results: https://trello.com/c/mOYNtDsH/2308-datepicker
    1. x5 keyboard navigation when open, parse input otherwsie, placeholder (WAI-ARIA, carbondesignsystem, bootstrap-datepicker, syncfusion, reactdatepicker, gmail)
    2. x1 hybrid arrow navigation, parse input, placeholder (google calendar)
    3. x1 keyboard selection cursor, keyboard navigation when open (kendo-ui)
    4. x1 keyboard navigation, no parse input, placeholder (react-dates)
    5. x5 no keyboard navigation, parse input, placeholder (react-day-picker, google analytics, ant design, blueprint, jquery-ui)
    6. x3 no keyboard navigation, no parse input (airbnb.com, booking.com, google flights)

@material-ui/pickers doesn't fit any of these categories, I have failed to describe it, I feel they are two possible modes. I have ranked the above categories in the order I feel they work the best. .ii vs .i feels like the difference between a combobox list vs combobox grid. However, I think that it's clear there isn't a single viable approach. Even If I have grouped them, I feel that they all have stubble differences. I hope it helps.

vdh commented 4 years ago

@dmtrKovalenko How does the current functionality work with supporting single vs double digit inputs, with regards to the masking?

But that's a good point about single digits, something like the 22nd of November would make for a better dummy date (new Date(2020, 10, 22)) so that there are always double digits for day and month in the generated mask.