diff --git a/webapp/channels/src/components/custom_status/date_time_input.test.tsx b/webapp/channels/src/components/custom_status/date_time_input.test.tsx index f434472aff..02426bdcf2 100644 --- a/webapp/channels/src/components/custom_status/date_time_input.test.tsx +++ b/webapp/channels/src/components/custom_status/date_time_input.test.tsx @@ -12,7 +12,7 @@ import * as i18Selectors from 'selectors/i18n'; import mockStore from 'tests/test_store'; -import DateTimeInput from './date_time_input'; +import DateTimeInput, {getTimeInIntervals} from './date_time_input'; jest.mock('selectors/i18n'); @@ -34,4 +34,17 @@ describe('components/custom_status/date_time_input', () => { ); expect(wrapper.dive()).toMatchSnapshot(); }); + + it.each([ + ['2024-03-02T02:00:00+0100', 48], + ['2024-03-31T02:00:00+0100', 46], + ['2024-10-07T02:00:00+0100', 48], + ['2024-10-27T02:00:00+0100', 48], + ['2025-01-01T03:00:00+0200', 48], + ])('should not infinitely loop on DST', (time, expected) => { + const timezone = 'Europe/Paris'; + + const intervals = getTimeInIntervals(moment.tz(time, timezone).startOf('day')); + expect(intervals).toHaveLength(expected); + }); }); diff --git a/webapp/channels/src/components/custom_status/date_time_input.tsx b/webapp/channels/src/components/custom_status/date_time_input.tsx index 9eaec36882..8d9a754cde 100644 --- a/webapp/channels/src/components/custom_status/date_time_input.tsx +++ b/webapp/channels/src/components/custom_status/date_time_input.tsx @@ -40,14 +40,21 @@ export function getRoundedTime(value: Moment) { return start.add(remainder, 'm').seconds(0).milliseconds(0); } -const getTimeInIntervals = (startTime: Moment): Date[] => { +export const getTimeInIntervals = (startTime: Moment): Date[] => { const interval = CUSTOM_STATUS_TIME_PICKER_INTERVALS_IN_MINUTES; let time = moment(startTime); const nextDay = moment(startTime).add(1, 'days').startOf('day'); + const intervals: Date[] = []; while (time.isBefore(nextDay)) { intervals.push(time.toDate()); + const utcOffset = time.utcOffset(); time = time.add(interval, 'minutes').seconds(0).milliseconds(0); + + // Account for DST end if needed to avoid displaying duplicates + if (utcOffset > time.utcOffset()) { + time = time.add(utcOffset - time.utcOffset(), 'minutes').seconds(0).milliseconds(0); + } } return intervals; @@ -113,7 +120,7 @@ const DateTimeInputContainer: React.FC = (props: Props) => { const handleTimeChange = useCallback((time: Date, e: React.MouseEvent) => { e.preventDefault(); - handleChange(moment(time)); + handleChange(timezone ? moment.tz(time, timezone) : moment(time)); focusTimeButton(); }, [handleChange]);