mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.08k stars 1.26k forks source link

[DatePicker] inconsistency between selecting and typing date #4848

Closed croraf closed 2 years ago

croraf commented 2 years ago

Current Behavior ๐Ÿ˜ฏ

When date is typed it puts time to 00:00 local time. (and timezone) When date is picked it puts time to current local time. (and timezone)

Expected Behavior ๐Ÿค”

The two should be consistent.

Steps to Reproduce ๐Ÿ•น

https://codesandbox.io/s/basicdatepicker-material-demo-forked-3zowk

Steps:

  1. Type date, and check the console.
  2. Clear date, pick date, and check the console.

Context ๐Ÿ”ฆ

Your Environment ๐ŸŒŽ

`npx @mui/envinfo` ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```
sudoshreyansh commented 2 years ago

Can I work on this issue ?

croraf commented 2 years ago

@sudoshreyansh What is your idea about how the logic should work?

BrenoVelasco commented 2 years ago

Hope I can help anyone with this issue that was opened on material-ui-pickers: https://github.com/mui-org/material-ui-pickers/issues/1526

Please read the thread as I think they were talking about the same issue. The possible solution they found was to treat this as the native input does:

Screen Shot 2021-10-12 at 10 54 10

I'm also facing the same problem where, sometimes, when I pick a certain date, what the client sends to the API is the day after. I'm currently in Brazil (Brasรญlia Time - BRT).

sudoshreyansh commented 2 years ago

@croraf I was thinking of ignoring the time and having the value as string, just like the native input element does.

@BrenoVelasco Thanks for the information. I believe they also reached the same conclusion.

croraf commented 2 years ago

I also think working with strings here is the best.

Buuut... this will be pretty intrusive for the component and don't know how will it interplay with the localization providers. You will have to change a lot internally, and the API will change a lot.

That said, DatePicker is in the @mui/lab, so you have my :+1: . You can start working on it, but be aware that maintainers might stop this. @eps1lon @oliviertassinari

ctbodycad commented 2 years ago

I have the same issue as @BrenoVelasco except that when I pick a certain date, what the client sends to the API is the day before. I'm in America EST time zone. My "onChangeDate" function correctly formats the date and has the right date when debugging, it's after the onChangeDate is executed that the DatePicker component goes back 1 day.

BrenoVelasco commented 2 years ago

@ctbodycad I grabbed a piece of code from the issue I mentioned above and it worked well for me. Hope it helps:

import { useCallback } from 'react'

import DateFnsUtils from '@date-io/date-fns'
import { DatePicker, DatePickerProps } from '@mui/lab'

/**
 * [DEPRECATED] This component refers to the material-ui-pickers lib issue:
 * https://github.com/mui-org/material-ui-pickers/issues/1526
 * This component refers to the mui lib issue:
 * https://github.com/mui-org/material-ui/issues/28922
 * This component disregards the client timezone when passing value to the material-ui-pickers component
 * @returns
 */

function jsDateToLocalISO8601DateString(date) {
  return [
    String(date.getFullYear()),
    String(101 + date.getMonth()).substring(1),
    String(100 + date.getDate()).substring(1),
  ].join('-')
}

function dateStringToLocalDate(s) {
  if (!s) return null
  return new DateFnsUtils().parse(s, 'yyyy-MM-dd')
}

export default function DatePickerWithWorkaround(
  props: Omit<DatePickerProps, 'onChange'> & { onChange: any },
) {
  const { value, onChange } = props

  const handleChange = useCallback(
    date => {
      onChange(date ? jsDateToLocalISO8601DateString(date) : null)
    },
    [onChange],
  )

  return (
    <DatePicker
      {...props}
      value={dateStringToLocalDate(value) ?? ''}
      onChange={handleChange}
    />
  )
}
ctbodycad commented 2 years ago

@BrenoVelasco I just solved this issue by using the way they specify the onChange prop in the examples ... when the correct inputFormat (ie the date format) is specified, we do not actually need to format the date in onChange. So basically:

function onChangeDate(date) { setValue(date) }

Did the trick for me, now my picker doesnt "travel back in time" and the input has the right format. Nice side effect is that the input has the correct mask applied, too (which was not the case due to the impact of reformatting. Hope that helps !

MarkMc9999 commented 2 years ago

I have found this thread and previous discussions because I used the KeyboardDatePicker to record a date-of-birth and was surprised when it went back a day because of the timezone issues.

Now giving this some thought, there are two perfectly legitimate use cases here;

  1. Picking a date, say for an expiry of an account - the logic of the situation may dictate that timezone matters here because even though it is an expiry date (lets assume expires 00:00 on the date in question in the users time zone). So if our server is hosted in a different time zone, then to get the exact expiry at that exact time, the server will need to act on the expiry (e.g. cancel an order or something like that) at a different local time.
  2. my use case Date is ambiguous of time - date-of-birth or anniversary of some kind seem to fit this model.

I gave up on the logic of the date/time converting in multiple places (web api gets involved as well.) My solution for DOB is actually to create my own picker with the day, month and year as separate dropdowns, and it returns an ISO date string in YYYY-MM-DD format.

If this control is to support both use cases, then it will obviously need some parameter to configure it to always be at 00:00 UTC for example?

flaviendelangle commented 2 years ago

The behavior is now coherent between selecting and typing. Since #4649, in both cases, we use midnight instead of the current time.

Are you sure the whole discussion about the timezone strictly relates to the initial pain of the issue ?

flaviendelangle commented 2 years ago

Closing from lack of feedback, and the initial pain has been resolved. You have issues strictly related to timezone if you want to continue the discussion :+1: