Fix date picker wrong on certain timezones (#5972)

Timezone with a negative offset weren't working good with date pickers.

I split the logic for display and parsing between date only and
datetime.

Date time is sending and displaying using timezone, and date only is
sending and displaying by forcing the date to take its UTC day and month
and 00:00:00 time.

This way its consistent across all timezones.
This commit is contained in:
Lucas Bordeau
2024-06-20 17:13:30 +02:00
committed by GitHub
parent 8c6e96c41b
commit 9e08445bff
7 changed files with 80 additions and 22 deletions

View File

@ -121,6 +121,7 @@ export const FieldInput = ({
onEscape={onEscape}
onClickOutside={onClickOutside}
onClear={onSubmit}
onSubmit={onSubmit}
/>
) : isFieldDate(fieldDefinition) ? (
<DateFieldInput
@ -128,6 +129,7 @@ export const FieldInput = ({
onEscape={onEscape}
onClickOutside={onClickOutside}
onClear={onSubmit}
onSubmit={onSubmit}
/>
) : isFieldNumber(fieldDefinition) ? (
<NumberFieldInput

View File

@ -13,6 +13,7 @@ export type DateFieldInputProps = {
onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent;
onClear?: FieldInputEvent;
onSubmit?: FieldInputEvent;
};
export const DateFieldInput = ({
@ -20,6 +21,7 @@ export const DateFieldInput = ({
onEscape,
onClickOutside,
onClear,
onSubmit,
}: DateFieldInputProps) => {
const { fieldValue, setDraftValue } = useDateField();
@ -39,6 +41,10 @@ export const DateFieldInput = ({
onEnter?.(() => persistDate(newDate));
};
const handleSubmit = (newDate: Nullable<Date>) => {
onSubmit?.(() => persistDate(newDate));
};
const handleEscape = (newDate: Nullable<Date>) => {
onEscape?.(() => persistDate(newDate));
};
@ -69,6 +75,7 @@ export const DateFieldInput = ({
clearable
onChange={handleChange}
onClear={handleClear}
onSubmit={handleSubmit}
/>
);
};

View File

@ -12,6 +12,7 @@ export type DateTimeFieldInputProps = {
onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent;
onClear?: FieldInputEvent;
onSubmit?: FieldInputEvent;
};
export const DateTimeFieldInput = ({
@ -19,6 +20,7 @@ export const DateTimeFieldInput = ({
onEscape,
onClickOutside,
onClear,
onSubmit,
}: DateTimeFieldInputProps) => {
const { fieldValue, setDraftValue } = useDateTimeField();
@ -57,6 +59,10 @@ export const DateTimeFieldInput = ({
onClear?.(() => persistDate(null));
};
const handleSubmit = (newDate: Nullable<Date>) => {
onSubmit?.(() => persistDate(newDate));
};
const dateValue = fieldValue ? new Date(fieldValue) : null;
return (
@ -69,6 +75,7 @@ export const DateTimeFieldInput = ({
onChange={handleChange}
isDateTimeInput
onClear={handleClear}
onSubmit={handleSubmit}
/>
);
};

View File

@ -142,10 +142,9 @@ export const RecordTableCellContainer = ({
[styles.cellBaseContainerSoftFocus]: hasSoftFocus,
})}
>
{isInEditMode && (
{isInEditMode ? (
<RecordTableCellEditMode>{editModeContent}</RecordTableCellEditMode>
)}
{hasSoftFocus ? (
) : hasSoftFocus ? (
<RecordTableCellSoftFocusMode
editModeContent={editModeContent}
nonEditModeContent={nonEditModeContent}

View File

@ -33,6 +33,7 @@ export type DateInputProps = {
onChange?: (newDate: Nullable<Date>) => void;
isDateTimeInput?: boolean;
onClear?: () => void;
onSubmit?: (newDate: Nullable<Date>) => void;
};
export const DateInput = ({
@ -44,6 +45,7 @@ export const DateInput = ({
onChange,
isDateTimeInput,
onClear,
onSubmit,
}: DateInputProps) => {
const [internalValue, setInternalValue] = useState(value);
@ -59,6 +61,11 @@ export const DateInput = ({
onClear?.();
};
const handleMouseSelect = (newDate: Date | null) => {
setInternalValue(newDate);
onSubmit?.(newDate);
};
const { closeDropdown } = useDropdown(MONTH_AND_YEAR_DROPDOWN_ID);
const { closeDropdown: closeDropdownMonthSelect } = useDropdown(
MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID,
@ -86,9 +93,7 @@ export const DateInput = ({
<InternalDatePicker
date={internalValue ?? new Date()}
onChange={handleChange}
onMouseSelect={(newDate: Date | null) => {
onEnter(newDate);
}}
onMouseSelect={handleMouseSelect}
clearable={clearable ? clearable : false}
isDateTimeInput={isDateTimeInput}
onEnter={onEnter}

View File

@ -57,11 +57,25 @@ export const DateTimeInput = ({
(date: any) => {
const dateParsed = DateTime.fromJSDate(date);
const formattedDate = dateParsed.toFormat(parsingFormat);
const dateWithoutTime = DateTime.fromJSDate(date)
.toLocal()
.set({
day: date.getUTCDate(),
month: date.getUTCMonth() + 1,
year: date.getUTCFullYear(),
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
});
const formattedDate = isDateTimeInput
? dateParsed.toFormat(parsingFormat)
: dateWithoutTime.toFormat(parsingFormat);
return formattedDate;
},
[parsingFormat],
[parsingFormat, isDateTimeInput],
);
const parseStringToDate = (str: string) => {

View File

@ -383,19 +383,35 @@ export const InternalDatePicker = ({
onChange?.(newDate);
};
const dateWithoutTime = DateTime.fromJSDate(date)
.toLocal()
.set({
day: date.getUTCDate(),
month: date.getUTCMonth() + 1,
year: date.getUTCFullYear(),
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
})
.toJSDate();
const dateToUse = isDateTimeInput ? date : dateWithoutTime;
return (
<StyledContainer onKeyDown={handleKeyDown}>
<div className={clearable ? 'clearable ' : ''}>
<ReactDatePicker
open={true}
selected={internalDate}
openToDate={internalDate}
selected={dateToUse}
openToDate={dateToUse}
disabledKeyboardNavigation
onChange={(newDate) => {
onChange?.(newDate);
}}
customInput={
<DateTimeInput
date={internalDate}
date={dateToUse}
isDateTimeInput={isDateTimeInput}
onChange={onChange}
/>
@ -424,13 +440,13 @@ export const InternalDatePicker = ({
options={months}
disableBlur
onChange={handleChangeMonth}
value={date.getMonth()}
value={date.getUTCMonth()}
fullWidth
/>
<Select
dropdownId={MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID}
onChange={handleChangeYear}
value={date.getFullYear()}
value={date.getUTCFullYear()}
options={years}
disableBlur
fullWidth
@ -450,16 +466,24 @@ export const InternalDatePicker = ({
</StyledCustomDatePickerHeader>
</>
)}
onSelect={(date: Date, event) => {
const dateUTC = DateTime.fromJSDate(date, {
zone: 'utc',
}).toJSDate();
onSelect={(date: Date) => {
const dateParsedWithoutTime = DateTime.fromObject(
{
day: date.getDate(),
month: date.getMonth() + 1,
year: date.getFullYear(),
hour: 0,
minute: 0,
second: 0,
},
{ zone: 'utc' },
).toJSDate();
if (event?.type === 'click') {
handleMouseSelect?.(dateUTC);
} else {
onChange?.(dateUTC);
}
const dateForUpdate = isDateTimeInput
? date
: dateParsedWithoutTime;
handleMouseSelect?.(dateForUpdate);
}}
/>
</div>