Skip to content

Commit 60bae65

Browse files
authored
Merge pull request marmelab#10311 from marmelab/fix-dateinput-shows-wrong-timezone
Fix DateInput ignores the timezone when given
2 parents b5aa5d4 + fd4f57c commit 60bae65

File tree

4 files changed

+35
-18
lines changed

4 files changed

+35
-18
lines changed

docs/DateInput.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@ import { DateInput } from 'react-admin';
2626
<DateInput source="published_at" />
2727
```
2828

29-
The field value must be a string with the pattern `YYYY-MM-DD` (ISO 8601), e.g. `'2022-04-30'`.
29+
The field value must be a string using the pattern `YYYY-MM-DD` (ISO 8601), e.g. `'2022-04-30'`. The returned input value will also be in this format, regardless of the browser locale.
30+
31+
`<DateInput>` also accepts values that can be converted to a `Date` object, such as:
32+
33+
- a localized date string (e.g. `'30/04/2022'`),
34+
- an ISO date string (e.g. `'2022-04-30T00:00:00.000Z'`),
35+
- a `Date` object, or
36+
- a Linux timestamp (e.g. `1648694400000`).
37+
38+
In these cases, `<DateInput>` will automatically convert the value to the `YYYY-MM-DD` format.
39+
40+
**Note**: This conversion may change the date because of timezones. For example, the date string `'2022-04-30T00:00:00.000Z'` in Europe may be displayed as `'2022-04-29'` in Honolulu. If this is not what you want, pass your own [`parse`](./Inputs.md#parse) function to `<DateInput>`.
3041

3142
## Props
3243

packages/ra-ui-materialui/src/input/DateInput.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ describe('<DateInput />', () => {
103103
it.each([
104104
'2021-09-11T20:46:20.000+02:00',
105105
'2021-09-11 20:46:20.000+02:00',
106-
'2021-09-11T20:46:20.000-04:00',
107-
'2021-09-11 20:46:20.000-04:00',
106+
'2021-09-10T20:46:20.000-04:00',
107+
'2021-09-10 20:46:20.000-04:00',
108108
'2021-09-11T20:46:20.000Z',
109109
'2021-09-11 20:46:20.000Z',
110110
])('should accept a value with timezone %s', async publishedAt => {

packages/ra-ui-materialui/src/input/DateInput.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const DefaultValue = () => (
6161
'2021-09-11 20:46:20.000Z',
6262
new Date('2021-09-11T20:46:20.000+02:00'),
6363
// although this one is 2021-09-10, its local timezone makes it 2021-09-11 in the test timezone
64-
new Date('2021-09-10T20:46:20.000-04:00'),
64+
new Date('2021-09-10T23:46:20.000-09:00'),
6565
new Date('2021-09-11T20:46:20.000Z'),
6666
1631385980000,
6767
].map((defaultValue, index) => (

packages/ra-ui-materialui/src/input/DateInput.tsx

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,22 +205,22 @@ export type DateInputProps = CommonInputProps &
205205
Omit<TextFieldProps, 'helperText' | 'label'>;
206206

207207
/**
208-
* Convert Date object to String, ignoring the timezone.
208+
* Convert Date object to String, using the local timezone
209209
*
210210
* @param {Date} value value to convert
211211
* @returns {String} A standardized date (yyyy-MM-dd), to be passed to an <input type="date" />
212212
*/
213213
const convertDateToString = (value: Date) => {
214214
if (!(value instanceof Date) || isNaN(value.getDate())) return '';
215-
let UTCDate = new Date(value.getTime() + value.getTimezoneOffset() * 60000);
215+
let localDate = new Date(value.getTime());
216216
const pad = '00';
217-
const yyyy = UTCDate.getFullYear().toString();
218-
const MM = (UTCDate.getMonth() + 1).toString();
219-
const dd = UTCDate.getDate().toString();
217+
const yyyy = localDate.getFullYear().toString();
218+
const MM = (localDate.getMonth() + 1).toString();
219+
const dd = localDate.getDate().toString();
220220
return `${yyyy}-${(pad + MM).slice(-2)}-${(pad + dd).slice(-2)}`;
221221
};
222222

223-
const dateRegex = /^(\d{4}-\d{2}-\d{2}).*$/;
223+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
224224
const defaultInputLabelProps = { shrink: true };
225225

226226
/**
@@ -234,14 +234,21 @@ const defaultInputLabelProps = { shrink: true };
234234
* - a Linux timestamp
235235
* - an empty string
236236
*
237+
* When it's not a bare date string (YYYY-MM-DD), the value is converted to
238+
* this format using the JS Date object.
239+
* THIS MAY CHANGE THE DATE VALUE depending on the browser locale.
240+
* For example, the string "09/11/2021" may be converted to "2021-09-10"
241+
* in Honolulu. This is expected behavior.
242+
* If this is not what you want, you should provide your own parse method.
243+
*
237244
* The output is always a string in the "YYYY-MM-DD" format.
238245
*
239246
* @example
240247
* defaultFormat('2021-09-11'); // '2021-09-11'
241-
* defaultFormat('09/11/2021'); // '2021-09-11'
242-
* defaultFormat('2021-09-11T20:46:20.000Z'); // '2021-09-11'
243-
* defaultFormat(new Date('2021-09-11T20:46:20.000Z')); // '2021-09-11'
244-
* defaultFormat(1631385980000); // '2021-09-11'
248+
* defaultFormat('09/11/2021'); // '2021-09-11' (may change depending on the browser locale)
249+
* defaultFormat('2021-09-11T20:46:20.000Z'); // '2021-09-11' (may change depending on the browser locale)
250+
* defaultFormat(new Date('2021-09-11T20:46:20.000Z')); // '2021-09-11' (may change depending on the browser locale)
251+
* defaultFormat(1631385980000); // '2021-09-11' (may change depending on the browser locale)
245252
* defaultFormat(''); // null
246253
*/
247254
const defaultFormat = (value: string | Date | number) => {
@@ -256,11 +263,10 @@ const defaultFormat = (value: string | Date | number) => {
256263
return convertDateToString(value);
257264
}
258265

259-
// Valid date strings should be stripped of their time and timezone parts.
266+
// Valid date strings (YYYY-MM-DD) should be considered as is
260267
if (typeof value === 'string') {
261-
const matches = dateRegex.exec(value);
262-
if (matches) {
263-
return matches[1];
268+
if (dateRegex.test(value)) {
269+
return value;
264270
}
265271
}
266272

0 commit comments

Comments
 (0)