diff --git a/packages/ui/src/elements/DatePicker/DatePicker.tsx b/packages/ui/src/elements/DatePicker/DatePicker.tsx index 714ec023d..c8c182b69 100644 --- a/packages/ui/src/elements/DatePicker/DatePicker.tsx +++ b/packages/ui/src/elements/DatePicker/DatePicker.tsx @@ -65,6 +65,13 @@ const DatePicker: React.FC = (props) => { const tzOffset = incomingDate.getTimezoneOffset() / 60 newDate.setHours(12 - tzOffset, 0) } + + if (newDate instanceof Date && !dateFormat.includes('SSS')) { + // Unless the dateFormat includes milliseconds, set milliseconds to 0 + // This is to ensure that the timestamp is consistent with the displayFormat + newDate.setMilliseconds(0) + } + if (typeof onChangeFromProps === 'function') { onChangeFromProps(newDate) } diff --git a/test/fields/collections/Date/e2e.spec.ts b/test/fields/collections/Date/e2e.spec.ts index 773d91a16..53e78f8b6 100644 --- a/test/fields/collections/Date/e2e.spec.ts +++ b/test/fields/collections/Date/e2e.spec.ts @@ -111,6 +111,70 @@ describe('Date', () => { await expect(dateField).toHaveValue('') }) + test('should clear miliseconds from dates with time', async () => { + await page.goto(url.create) + const dateField = page.locator('#field-default input') + await expect(dateField).toBeVisible() + // Fill in required fields, this is just to make sure saving is possible + await dateField.fill('02/07/2023') + const dateWithTz = page.locator('#field-dayAndTimeWithTimezone .react-datepicker-wrapper input') + + await dateWithTz.fill('08/12/2027 10:00 AM') + + const dropdownControlSelector = `#field-dayAndTimeWithTimezone .rs__control` + const timezoneOptionSelector = `#field-dayAndTimeWithTimezone .rs__menu .rs__option:has-text("London")` + + await page.click(dropdownControlSelector) + await page.click(timezoneOptionSelector) + + // Test the time field + const timeField = page.locator('#field-timeOnly input') + await timeField.fill('08/12/2027 10:00:00.123 AM') + + await saveDocAndAssert(page) + + const id = page.url().split('/').pop() + + const { doc } = await client.findByID({ id: id!, auth: true, slug: 'date-fields' }) + + await expect(() => { + // Ensure that the time field does not contain milliseconds + expect(doc?.timeOnly).toContain('00:00.000Z') + }).toPass() + }) + + test("should keep miliseconds when they're provided in the date format", async () => { + await page.goto(url.create) + const dateField = page.locator('#field-default input') + await expect(dateField).toBeVisible() + // Fill in required fields, this is just to make sure saving is possible + await dateField.fill('02/07/2023') + const dateWithTz = page.locator('#field-dayAndTimeWithTimezone .react-datepicker-wrapper input') + + await dateWithTz.fill('08/12/2027 10:00 AM') + + const dropdownControlSelector = `#field-dayAndTimeWithTimezone .rs__control` + const timezoneOptionSelector = `#field-dayAndTimeWithTimezone .rs__menu .rs__option:has-text("London")` + + await page.click(dropdownControlSelector) + await page.click(timezoneOptionSelector) + + // Test the time field + const timeField = page.locator('#field-timeOnlyWithMiliseconds input') + await timeField.fill('6:00.00.625 PM') + + await saveDocAndAssert(page) + + const id = page.url().split('/').pop() + + const { doc } = await client.findByID({ id: id!, auth: true, slug: 'date-fields' }) + + await expect(() => { + // Ensure that the time with miliseconds field contains the exact miliseconds specified + expect(doc?.timeOnlyWithMiliseconds).toContain('625Z') + }).toPass() + }) + describe('localized dates', () => { describe('EST', () => { test.use({ diff --git a/test/fields/collections/Date/index.ts b/test/fields/collections/Date/index.ts index 4e4b21a54..a5f94152e 100644 --- a/test/fields/collections/Date/index.ts +++ b/test/fields/collections/Date/index.ts @@ -24,6 +24,16 @@ const DateFields: CollectionConfig = { }, }, }, + { + name: 'timeOnlyWithMiliseconds', + type: 'date', + admin: { + date: { + pickerAppearance: 'timeOnly', + displayFormat: 'h:mm.ss.SSS aa', + }, + }, + }, { name: 'timeOnlyWithCustomFormat', type: 'date', diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 66f662245..a2a6340ec 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -903,6 +903,7 @@ export interface DateField { id: string; default: string; timeOnly?: string | null; + timeOnlyWithMiliseconds?: string | null; timeOnlyWithCustomFormat?: string | null; dayOnly?: string | null; dayAndTime?: string | null; @@ -2486,6 +2487,7 @@ export interface CustomRowIdSelect { export interface DateFieldsSelect { default?: T; timeOnly?: T; + timeOnlyWithMiliseconds?: T; timeOnlyWithCustomFormat?: T; dayOnly?: T; dayAndTime?: T;