diff --git a/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts b/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts index ab7f24db25..65b77ce5cf 100644 --- a/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts +++ b/web/src/lib/modals/AssetSelectionChangeDateModal.spec.ts @@ -71,6 +71,34 @@ describe('DateSelectionModal component', () => { expect(onClose).toHaveBeenCalled(); }); + test('does not fall back to UTC when datetime-local value has no seconds', async () => { + render(AssetSelectionChangeDateModal, { + props: { initialDate, initialTimeZone, assets: [], onClose }, + }); + + await fireEvent.input(getDateInput(), { target: { value: '2024-01-01T00:00' } }); + await fireEvent.blur(getDateInput()); + + expect(getTimeZoneInput().value).toBe('Europe/Berlin (+01:00)'); + + await fireEvent.focus(getTimeZoneInput()); + expect(screen.queryByText('no_results')).not.toBeInTheDocument(); + }); + + test('does not fall back to UTC when datetime-local value has no milliseconds', async () => { + render(AssetSelectionChangeDateModal, { + props: { initialDate, initialTimeZone, assets: [], onClose }, + }); + + await fireEvent.input(getDateInput(), { target: { value: '2024-01-01T00:00:00' } }); + await fireEvent.blur(getDateInput()); + + expect(getTimeZoneInput().value).toBe('Europe/Berlin (+01:00)'); + + await fireEvent.focus(getTimeZoneInput()); + expect(screen.queryByText('no_results')).not.toBeInTheDocument(); + }); + describe('when date is in daylight saving time', () => { const dstDate = DateTime.fromISO('2024-07-01'); diff --git a/web/src/lib/modals/timezone-utils.ts b/web/src/lib/modals/timezone-utils.ts index fc4081d3bb..157c736dfb 100644 --- a/web/src/lib/modals/timezone-utils.ts +++ b/web/src/lib/modals/timezone-utils.ts @@ -75,8 +75,15 @@ function zoneOptionForDate(zone: string, date: string) { // Ignore milliseconds: // - milliseconds are not relevant for TZ calculations // - browsers strip insignificant .000 making string comparison with milliseconds more fragile. + // + // Also, some browsers emit `datetime-local` values without seconds when seconds are 00, + // e.g. `2024-01-01T00:00` instead of `2024-01-01T00:00:00.000`. + // In that case we must compare with minute precision (otherwise every zone looks "invalid"). const dateInTimezone = DateTime.fromISO(date, { zone }); - const exists = date.replace(/\.\d+/, '') === dateInTimezone.toFormat("yyyy-MM-dd'T'HH:mm:ss"); + const withoutMillis = date.replace(/\.\d+/, ''); + const hasSeconds = /T\d{2}:\d{2}:\d{2}$/.test(withoutMillis); + const compareFormat = hasSeconds ? "yyyy-MM-dd'T'HH:mm:ss" : "yyyy-MM-dd'T'HH:mm"; + const exists = withoutMillis === dateInTimezone.toFormat(compareFormat); const valid = dateInTimezone.isValid && exists; return { value: zone,