diff --git a/change/@fluentui-react-c9b264cb-f787-48ed-a936-6359e1efa00e.json b/change/@fluentui-react-c9b264cb-f787-48ed-a936-6359e1efa00e.json new file mode 100644 index 00000000000000..0ca6fbd71c2ec9 --- /dev/null +++ b/change/@fluentui-react-c9b264cb-f787-48ed-a936-6359e1efa00e.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix(TimePicker): Selection now works in locales that don't use \"am\"/\"pm\" in their time format", + "packageName": "@fluentui/react", + "email": "behowell@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react/src/components/TimePicker/TimePicker.test.tsx b/packages/react/src/components/TimePicker/TimePicker.test.tsx index c335bfea34912d..6b59c63e10fb8d 100644 --- a/packages/react/src/components/TimePicker/TimePicker.test.tsx +++ b/packages/react/src/components/TimePicker/TimePicker.test.tsx @@ -119,6 +119,33 @@ describe('TimePicker', () => { expect(formattedSelectedTime).toEqual(expectedTime); }); + it('allows time selection in locales that format time without "am/pm"', () => { + const { toLocaleTimeString } = Date.prototype; + const toLocaleTimeStringMock = jest.spyOn(Date.prototype, 'toLocaleTimeString'); + + // Mock toLocaleTimeString to simulate running in a Japanese locale + toLocaleTimeStringMock.mockImplementation(function (this: Date, _locales, options) { + return toLocaleTimeString.call(this, 'ja-JP', options); + }); + + const dateAnchor = new Date('February 27, 2023 08:00:00'); + + const onChange = jest.fn(); + + const { getByRole, getAllByRole } = render( + , + ); + + const timePickerComboBox = getByRole('combobox') as HTMLInputElement; + userEvent.click(timePickerComboBox); + const timePickerOptions = getAllByRole('option') as HTMLButtonElement[]; + userEvent.click(timePickerOptions[2], undefined, { skipPointerEventsCheck: true }); + + expect(onChange).toHaveBeenLastCalledWith(expect.anything(), new Date('February 27, 2023 08:30:00')); + + toLocaleTimeStringMock.mockRestore(); + }); + it('correctly renders options using default value as date anchor', () => { const defaultValue = new Date('April 1, 2023 13:00:00'); diff --git a/packages/react/src/components/TimePicker/TimePicker.tsx b/packages/react/src/components/TimePicker/TimePicker.tsx index 2442d38b065cab..0895a612b9609f 100644 --- a/packages/react/src/components/TimePicker/TimePicker.tsx +++ b/packages/react/src/components/TimePicker/TimePicker.tsx @@ -89,6 +89,7 @@ export const TimePicker: React.FunctionComponent = ({ return { key: formattedTimeString, text: optionText, + data: option, }; }); }, [dateStartAnchor, increments, optionsCount, showSeconds, onFormatDate, useHour12]); @@ -156,8 +157,13 @@ export const TimePicker: React.FunctionComponent = ({ setSelectedTime(errorMessageToDisplay ? new Date('invalid') : undefined); changedTime = new Date('invalid'); } else { - const timeSelection = (option?.key as string) || input || ''; - const updatedTime = getDateFromTimeSelection(useHour12, dateStartAnchor, timeSelection); + let updatedTime; + if (option?.data instanceof Date) { + updatedTime = option.data; + } else { + const timeSelection = (option?.key as string) || input || ''; + updatedTime = getDateFromTimeSelection(useHour12, dateStartAnchor, timeSelection); + } setSelectedTime(updatedTime); changedTime = updatedTime; }