sumcumo / vue-datepicker

A datepicker Vue component. Compatible with Vue 2.x.
https://sumcumo.github.io/vue-datepicker/
Apache License 2.0
75 stars 22 forks source link

How to interpret typed dates entered in simplified ISO 8601 format? #160

Open mst101 opened 2 years ago

mst101 commented 2 years ago

When JavaScript parses dates, it assumes a timezone of UTC whenever it recognises a date string as being a simplification of the ISO 8601 format. e.g. '2000-01-01' is assumed to be in UTC timezone.

However, non-standard date strings are parsed using the browser's local timezone e.g. '1 January 2000' uses your browser's timezone. See example.

This begs the question as to how we should handle any such simplified ISO 8601 dates that a user may enter into a typeable datepicker...

Assuming use-utc is false, should we:

a) Continue with the existing behaviour and allow users to be potentially baffled as to why when they enter a date such as '2000-01-01', depending on their browser's timezone, the datepicker actually selects a date representing the previous day?

b) Try to catch any dates a user enters that the browser may interpret as being in simplified ISO 8601 format and convert them to a local timezone date instead?

Similarly in the scenario where use-utc is true, should we interpret all typed dates as being in UTC timezone, including those which would normally be parsed using the browser's local timezone such as '1 January 2000'?

A further complication: What about if the user actually specifies a timezone e.g. '1 January 2000 EST' or '2000-01-01T00:00:00.000-05:00'? Should we use it, or not? If we do, we'd need to run all typed dates against a regex to determine whether or not a timezone has been added - and while the [+-]hh:mm scenario could be interpreted reasonably easily, it appears the three letter abbreviations are inconsistent e.g. does BST mean 'British Summer Time' or 'Bangladesh Standard Time'? The only ones I've found Chrome/Firefox to actually use are: UTC, GMT, EDT, EST, CDT, CST, MDT, MST, PDT and PST.

MrWook commented 2 years ago

I think the use-utc seems kind of buggy. But for example if you have the date "2022-06-06" and use it in the js browser like this new Date('2022-06-06') you will get Sun Jun 05 2022 17:00:00 GMT-0700 (Pacific Daylight Time) which is basically the same as what you get if you use use-utc

The best case is if we can achieve that no timezone is used at all. So that the user will always get the selected start of the day that the user selected. Which should be the case without use-utc 🤔

mst101 commented 2 years ago

I think the use-utc seems kind of buggy.

I've spent quite a while looking into this and this is what I've found:

  1. The use-utc prop works fine, provided you're consistent about which format (UTC vs local) you input/output the dates.

There are 4 props that allow you to input dates:

:value
:open-date
:disabled-dates
:highlighted

-> If use-utc is false, you should input these dates as local dates and expect a local date as output -> If use-utc is true, you should input these dates as UTC dates and expect a UTC date as output

  1. Problems may occur whenever a date string is parsed. Indeed, what prompted me to raise this issue was the apparent inconsistency in the way a 'typeable' datepicker handles date strings that a user may type in the input field:

For example, if you type '01 Jan 2000', you will be entering a local date (so if you're in Germany, that means selectedDate will be one hour before midnight in Greenwich), but if you type '2000-01-01' you will be entering a UTC date (so selectedDate will be midnight in Greenwich). Just to complicate matters further (and I wasn't aware of this until recently...), as soon as you add a time to a date that's in ISO 8601 format e.g. '2000-01-01T00:00', JavaScript interprets this as a local date! See fiddle.

These issues arise not only when a user types dates into a typeable calendar, but also when a developer inputs dates in a string format via the props. Currently, for :disabled-dates and :highlighted, this fails silently for any values that are not a valid date object. :value and :open-date, however, are an issue as these do interpret date strings as new Date(dateString), so they are prone to the timezone issues described above (unless the developer really knows their JavaScript dates!).

One solution would be to forbid date strings and force developers to input their dates either as date objects, or timestamps. We would throw a descriptive error whenever a date string is found.

Another solution may be to flag up any inconsistencies between date strings that have been inputted via props and the value of use-utc. We would have to run the date strings through a function to check them against a regex which determines whether they are going to be interpreted as UTC, or not. However, I fear this would be quite complicated and also error prone.

So, I think my preferred solution would be to simply ban people from entering date strings via the props!

We should also add a section on 'UTC dates' in the documentation that clearly explains the need to input local dates when use-utc is false and UTC dates when use-utc is true. This section can also describe some common gotchas as described above e.g. if use-utc is false, you should enter dates as new Date(2000, 0, 1), not new Date('2000-01-01').

This doesn't solve the original issue of how to interpret dates that are typed into a typeable calendar, but since I'm the only person that's raised this so far, perhaps it isn't a very common problem!

@MrWook - your thoughts?

mst101 commented 2 years ago

Since writing this, I've softened my view on allowing date strings as props. After all, there's nothing that stops someone from changing this:

<Datepicker value="2000-01-01" />

to this:

<Datepicker value="new Date('2000-01-01')" />

...so we may as well allow them. I do think it's important though to have some documentation that explains the difference between local dates and UTC dates to help prevent developers from making errors and I'll submit a PR for this shortly.

The only thing that I'm unsure of now is whether we should also allow timestamps and date strings in the disabled-dates and highlighted props in order to be consistent. Or, do we keep the current requirement to enter these values as dates and either print a warning to the console or throw an error when non-date values are detected?

What do you think?