Skip to content

Commit 74938a3

Browse files
committed
fix(date, date-range): ensure date format override returns correct formatted value
When overridding the default date format, the format was not always respected and would switch to the default in some cases where the day and month were flipped. fix #7345
1 parent d802eb4 commit 74938a3

File tree

10 files changed

+485
-143
lines changed

10 files changed

+485
-143
lines changed

src/components/date-range/date-range.component.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export const DateRange = ({
149149
endRef,
150150
required,
151151
isOptional,
152+
dateFormatOverride: dateFormatOverrideProp,
152153
datePickerStartAriaLabel,
153154
datePickerStartAriaLabelledBy,
154155
datePickerEndAriaLabel,
@@ -169,8 +170,12 @@ export const DateRange = ({
169170
const l = useLocale();
170171
const { dateFnsLocale, dateFormatOverride } = l.date;
171172
const { format } = useMemo(
172-
() => getFormatData(dateFnsLocale(), dateFormatOverride),
173-
[dateFnsLocale, dateFormatOverride],
173+
() =>
174+
getFormatData(
175+
dateFnsLocale(),
176+
dateFormatOverrideProp || dateFormatOverride,
177+
),
178+
[dateFnsLocale, dateFormatOverrideProp, dateFormatOverride],
174179
);
175180
const inlineLabelWidth = 40;
176181
const [lastChangedDate, setLastChangedDate] = useState("");

src/components/date-range/date-range.test.tsx

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from "react";
22
import { render, screen, within } from "@testing-library/react";
33
import userEvent from "@testing-library/user-event";
44
import { enGB as enGBLocale } from "date-fns/locale/en-GB";
5-
import { de as deLocale } from "date-fns/locale/de";
65

76
import DateRange, { DateRangeChangeEvent } from "./date-range.component";
87
import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils";
@@ -1219,17 +1218,17 @@ test("should have the default styling when the `labelsInline` prop is set and `v
12191218
});
12201219

12211220
describe("Locale formatting overrides", () => {
1222-
test("should render with the input value matching the expected format when `dateFormatOverride` is set and the language is `de-DE`", () => {
1221+
it("should render with the input value matching the expected format when `dateFormatOverride` is passed as a translation key", () => {
12231222
render(
12241223
<I18nProvider
12251224
locale={{
1226-
locale: () => "de-DE",
1225+
locale: () => "en-GB",
12271226
date: {
12281227
ariaLabels: {
12291228
nextMonthButton: () => "foo",
12301229
previousMonthButton: () => "foo",
12311230
},
1232-
dateFnsLocale: () => deLocale,
1231+
dateFnsLocale: () => enGBLocale,
12331232
dateFormatOverride: "y-m-ddd",
12341233
},
12351234
}}
@@ -1251,28 +1250,15 @@ describe("Locale formatting overrides", () => {
12511250
);
12521251
});
12531252

1254-
test("should render with the input value matching the expected format when `dateFormatOverride` is set and the language is `en-GB`", () => {
1253+
it("should render with the input value matching the expected format when `dateFormatOverride` is passed as a prop", () => {
12551254
render(
1256-
<I18nProvider
1257-
locale={{
1258-
locale: () => "en-GB",
1259-
date: {
1260-
ariaLabels: {
1261-
nextMonthButton: () => "foo",
1262-
previousMonthButton: () => "foo",
1263-
},
1264-
dateFnsLocale: () => enGBLocale,
1265-
dateFormatOverride: "y-m-ddd",
1266-
},
1267-
}}
1268-
>
1269-
<DateRange
1270-
startLabel="start"
1271-
endLabel="end"
1272-
value={["2016-10-10", "2016-11-11"]}
1273-
onChange={() => {}}
1274-
/>
1275-
</I18nProvider>,
1255+
<DateRange
1256+
startLabel="start"
1257+
endLabel="end"
1258+
value={["2016-10-10", "2016-11-11"]}
1259+
onChange={() => {}}
1260+
dateFormatOverride="y-m-ddd"
1261+
/>,
12761262
);
12771263

12781264
expect(screen.getByRole("textbox", { name: "start" })).toHaveValue(

src/components/date/__internal__/date-formats/date-formats.test.ts

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -511,33 +511,59 @@ test("should default to en-GB locale if no locale code string passed to `getForm
511511
});
512512

513513
describe("dateFormatOverride tests", () => {
514-
const localeCodes = [
515-
// handled locales
516-
"en-CA",
517-
"en-US",
518-
"en-ZA",
519-
"fr-CA",
520-
"ar-EG",
521-
// random locale to cover default switch scenario
522-
"zh-HK",
523-
];
524-
const dateFormatOverride = "dd Mo yyyy";
525-
526-
test.each(localeCodes)(
527-
"should support %s locale code string passed to `getFormatData` when dateFormatOverride is provided",
528-
(code: string) => {
529-
const { formats, format } = getFormatData({ code }, dateFormatOverride);
530-
531-
const expectedFormats = getExpectedFormatForLocale(code);
532-
533-
expect(
534-
expectedFormats.every((formatStr) => formats.includes(formatStr)) &&
535-
formats.length === expectedFormats.length,
536-
).toEqual(true);
537-
538-
expect(format).toEqual(dateFormatOverride);
539-
},
540-
);
514+
test("should return the expected formats when `dateFormatOverride` is passed as NA locale", () => {
515+
const dateFormatOverride = "MM/dd/yyyy";
516+
const { formats, format } = getFormatData(
517+
{ code: "en-GB" },
518+
dateFormatOverride,
519+
);
520+
521+
// since the dateFormatOverride starts with the month, it should be treated as a NA locale
522+
const expectedFormats = getExpectedFormatForLocale("en-US");
523+
524+
expect(
525+
expectedFormats.every((formatStr) => formats.includes(formatStr)) &&
526+
formats.length === expectedFormats.length,
527+
).toEqual(true);
528+
529+
expect(format).toEqual(dateFormatOverride);
530+
});
531+
532+
test("should return the expected formats when `dateFormatOverride` is passed as EU locale", () => {
533+
const dateFormatOverride = "dd/MM/yyyy";
534+
const { formats, format } = getFormatData(
535+
{ code: "en-US" },
536+
dateFormatOverride,
537+
);
538+
539+
// since the dateFormatOverride starts with the day, it should be treated as a EU locale
540+
const expectedFormats = getExpectedFormatForLocale("en-GB");
541+
542+
expect(
543+
expectedFormats.every((formatStr) => formats.includes(formatStr)) &&
544+
formats.length === expectedFormats.length,
545+
).toEqual(true);
546+
547+
expect(format).toEqual(dateFormatOverride);
548+
});
549+
550+
test("should return the expected formats when `dateFormatOverride` is passed as CN locale", () => {
551+
const dateFormatOverride = "yyyy/MM/dd";
552+
const { formats, format } = getFormatData(
553+
{ code: "en-GB" },
554+
dateFormatOverride,
555+
);
556+
557+
// since the dateFormatOverride starts with the year, it should be treated as a CN locale
558+
const expectedFormats = getExpectedFormatForLocale("zh");
559+
560+
expect(
561+
expectedFormats.every((formatStr) => formats.includes(formatStr)) &&
562+
formats.length === expectedFormats.length,
563+
).toEqual(true);
564+
565+
expect(format).toEqual(dateFormatOverride);
566+
});
541567
});
542568

543569
describe.each(euLocales)(

src/components/date/__internal__/date-formats/index.ts

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -145,51 +145,30 @@ const getFormatData = (
145145
dateFormatOverride?: string,
146146
): LocaleFormats => {
147147
const code = locale?.code || "en-GB";
148-
if (dateFormatOverride) {
149-
const { format } = getOutputFormatForLocale(code);
150-
let formatFromLocale;
151-
152-
switch (code) {
153-
case "en-CA":
154-
case "en-US":
155-
formatFromLocale = "MM/dd/yyyy";
156-
break;
157-
case "ar-EG":
158-
case "en-ZA":
159-
case "fr-CA":
160-
formatFromLocale = "dd/MM/yyyy";
161-
break;
162-
default:
163-
formatFromLocale = format;
164-
}
165148

166-
const formatsForLocale = getInputFormatsArrayForLocale(formatFromLocale);
149+
const dateFnsFormatOverrides: Record<
150+
string,
151+
{ format: string; separator?: Separator }
152+
> = {
153+
"en-CA": { format: "MM/dd/yyyy", separator: "/" },
154+
"en-US": { format: "MM/dd/yyyy", separator: "/" },
155+
"fr-CA": { format: "dd/MM/yyyy" },
156+
"en-ZA": { format: "dd/MM/yyyy" },
157+
"ar-EG": { format: "dd/MM/yyyy" },
158+
};
167159

168-
return {
169-
format: dateFormatOverride,
170-
formats: generateFormats(formatsForLocale, "/"),
171-
};
172-
}
160+
const { format: defaultFormat, separator: defaultSeparator } =
161+
getOutputFormatForLocale(code);
173162

174-
if (["en-CA", "en-US"].includes(code)) {
175-
const format = "MM/dd/yyyy";
176-
const formats = getInputFormatsArrayForLocale(format);
177-
return {
178-
format,
179-
formats: generateFormats(formats, "/"),
180-
};
181-
}
163+
const override = dateFnsFormatOverrides[code] || {};
182164

183-
const { format, separator } = getOutputFormatForLocale(code);
184-
const outputFormat = ["fr-CA", "en-ZA", "ar-EG"].includes(code)
185-
? "dd/MM/yyyy"
186-
: format;
187-
const formatsForLocale = getInputFormatsArrayForLocale(outputFormat);
165+
const format = dateFormatOverride ?? override.format ?? defaultFormat;
166+
const separator = override.separator ?? defaultSeparator;
188167

189168
return {
190-
format: outputFormat,
169+
format,
191170
formats: generateFormats(
192-
formatsForLocale,
171+
getInputFormatsArrayForLocale(format),
193172
separator,
194173
getTrailingChar(format),
195174
),

0 commit comments

Comments
 (0)