diff --git a/docs/DateInput.md b/docs/DateInput.md
index 262d464462..92186fe85a 100644
--- a/docs/DateInput.md
+++ b/docs/DateInput.md
@@ -26,7 +26,18 @@ import { DateInput } from 'react-admin';
```
-The field value must be a string with the pattern `YYYY-MM-DD` (ISO 8601), e.g. `'2022-04-30'`.
+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.
+
+`` also accepts values that can be converted to a `Date` object, such as:
+
+- a localized date string (e.g. `'30/04/2022'`),
+- an ISO date string (e.g. `'2022-04-30T00:00:00.000Z'`),
+- a `Date` object, or
+- a Linux timestamp (e.g. `1648694400000`).
+
+In these cases, `` will automatically convert the value to the `YYYY-MM-DD` format.
+
+**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 ``.
## Props
diff --git a/packages/ra-ui-materialui/src/input/DateInput.spec.tsx b/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
index 2524698847..8aaeb5da2a 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
@@ -103,8 +103,8 @@ describe('', () => {
it.each([
'2021-09-11T20:46:20.000+02:00',
'2021-09-11 20:46:20.000+02:00',
- '2021-09-11T20:46:20.000-04:00',
- '2021-09-11 20:46:20.000-04:00',
+ '2021-09-10T20:46:20.000-04:00',
+ '2021-09-10 20:46:20.000-04:00',
'2021-09-11T20:46:20.000Z',
'2021-09-11 20:46:20.000Z',
])('should accept a value with timezone %s', async publishedAt => {
diff --git a/packages/ra-ui-materialui/src/input/DateInput.stories.tsx b/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
index b41457ef54..26f6bcdbff 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
@@ -61,7 +61,7 @@ export const DefaultValue = () => (
'2021-09-11 20:46:20.000Z',
new Date('2021-09-11T20:46:20.000+02:00'),
// although this one is 2021-09-10, its local timezone makes it 2021-09-11 in the test timezone
- new Date('2021-09-10T20:46:20.000-04:00'),
+ new Date('2021-09-10T23:46:20.000-09:00'),
new Date('2021-09-11T20:46:20.000Z'),
1631385980000,
].map((defaultValue, index) => (
diff --git a/packages/ra-ui-materialui/src/input/DateInput.tsx b/packages/ra-ui-materialui/src/input/DateInput.tsx
index 4bba3ae61a..7eff1db638 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.tsx
@@ -205,22 +205,22 @@ export type DateInputProps = CommonInputProps &
Omit;
/**
- * Convert Date object to String, ignoring the timezone.
+ * Convert Date object to String, using the local timezone
*
* @param {Date} value value to convert
* @returns {String} A standardized date (yyyy-MM-dd), to be passed to an
*/
const convertDateToString = (value: Date) => {
if (!(value instanceof Date) || isNaN(value.getDate())) return '';
- let UTCDate = new Date(value.getTime() + value.getTimezoneOffset() * 60000);
+ let localDate = new Date(value.getTime());
const pad = '00';
- const yyyy = UTCDate.getFullYear().toString();
- const MM = (UTCDate.getMonth() + 1).toString();
- const dd = UTCDate.getDate().toString();
+ const yyyy = localDate.getFullYear().toString();
+ const MM = (localDate.getMonth() + 1).toString();
+ const dd = localDate.getDate().toString();
return `${yyyy}-${(pad + MM).slice(-2)}-${(pad + dd).slice(-2)}`;
};
-const dateRegex = /^(\d{4}-\d{2}-\d{2}).*$/;
+const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
const defaultInputLabelProps = { shrink: true };
/**
@@ -234,14 +234,21 @@ const defaultInputLabelProps = { shrink: true };
* - a Linux timestamp
* - an empty string
*
+ * When it's not a bare date string (YYYY-MM-DD), the value is converted to
+ * this format using the JS Date object.
+ * THIS MAY CHANGE THE DATE VALUE depending on the browser locale.
+ * For example, the string "09/11/2021" may be converted to "2021-09-10"
+ * in Honolulu. This is expected behavior.
+ * If this is not what you want, you should provide your own parse method.
+ *
* The output is always a string in the "YYYY-MM-DD" format.
*
* @example
* defaultFormat('2021-09-11'); // '2021-09-11'
- * defaultFormat('09/11/2021'); // '2021-09-11'
- * defaultFormat('2021-09-11T20:46:20.000Z'); // '2021-09-11'
- * defaultFormat(new Date('2021-09-11T20:46:20.000Z')); // '2021-09-11'
- * defaultFormat(1631385980000); // '2021-09-11'
+ * defaultFormat('09/11/2021'); // '2021-09-11' (may change depending on the browser locale)
+ * defaultFormat('2021-09-11T20:46:20.000Z'); // '2021-09-11' (may change depending on the browser locale)
+ * defaultFormat(new Date('2021-09-11T20:46:20.000Z')); // '2021-09-11' (may change depending on the browser locale)
+ * defaultFormat(1631385980000); // '2021-09-11' (may change depending on the browser locale)
* defaultFormat(''); // null
*/
const defaultFormat = (value: string | Date | number) => {
@@ -256,11 +263,10 @@ const defaultFormat = (value: string | Date | number) => {
return convertDateToString(value);
}
- // Valid date strings should be stripped of their time and timezone parts.
+ // Valid date strings (YYYY-MM-DD) should be considered as is
if (typeof value === 'string') {
- const matches = dateRegex.exec(value);
- if (matches) {
- return matches[1];
+ if (dateRegex.test(value)) {
+ return value;
}
}