Skip to content

Commit 72ccd4b

Browse files
authored
fix: dateFns wrong format when typing date (#817)
* fix: dateFns wrong format when typing date * test(date fns): typing a date should not parse it if not complete
1 parent 7cf70bf commit 72ccd4b

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

src/generate/dateFns.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ const localeParse = (format: string) => {
4444
.replace(/([Ww])o/g, 'wo');
4545
};
4646

47+
const parse = (text: string, format: string, locale: string) => {
48+
return parseDate(text, localeParse(format), new Date(), { locale: getLocale(locale) });
49+
}
50+
51+
/**
52+
* Check if the text is a valid date considering the format and locale
53+
*
54+
* This is a strict check, the date string must match the format exactly.
55+
* Date-fns allows some flexibility in parsing dates, for example, it will parse "30/01/2" as "30/01/002".
56+
* This behavior is not desirable in our case, so we need to check if the date string matches the format exactly.
57+
*
58+
* @param text the date string
59+
* @param format the date format to use
60+
* @param locale the locale to use
61+
*/
62+
const isStrictValidDate = (text: string, format: string, locale: string) => {
63+
const date = parse(text, format, locale);
64+
if (!isValid(date)) {
65+
return false;
66+
}
67+
const formattedDate = formatDate(date, format, { locale: getLocale(locale) });
68+
return text === formattedDate;
69+
}
70+
4771
const generateConfig: GenerateConfig<Date> = {
4872
// get
4973
getNow: () => new Date(),
@@ -106,12 +130,9 @@ const generateConfig: GenerateConfig<Date> = {
106130
parse: (locale, text, formats) => {
107131
for (let i = 0; i < formats.length; i += 1) {
108132
const format = localeParse(formats[i]);
109-
const formatText = text;
110-
const date = parseDate(formatText, format, new Date(), {
111-
locale: getLocale(locale),
112-
});
113-
if (isValid(date)) {
114-
return date;
133+
134+
if (isStrictValidDate(text, format, locale)) {
135+
return parse(text, format, locale);
115136
}
116137
}
117138
return null;

tests/keyboard.spec.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import KeyCode from 'rc-util/lib/KeyCode';
33
import { resetWarned } from 'rc-util/lib/warning';
44
import React from 'react';
55
import {
6-
closePicker,
6+
closePicker, DateFnsSinglePicker,
77
DayPicker,
88
DayPickerPanel,
99
DayRangePicker,
@@ -130,6 +130,22 @@ describe('Picker.Keyboard', () => {
130130
});
131131
});
132132

133+
describe('typing date with date-fns', () => {
134+
it('should not parse date if not matching format', () => {
135+
const { container } = render(<DateFnsSinglePicker format="dd/MM/YYYY" />);
136+
const input = container.querySelector('input');
137+
138+
fireEvent.change(input, {
139+
target: {
140+
// Typing date partially. Picker should not try to parse it as a valid date
141+
value: "01/01/20",
142+
},
143+
});
144+
145+
expect(input.value).toEqual("01/01/20");
146+
});
147+
})
148+
133149
return;
134150
it('open to select', () => {
135151
const onChange = jest.fn();

tests/util/commonUtil.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
import dayGenerateConfig from '../../src/generate/dayjs';
2525
import enUS from '../../src/locale/en_US';
2626
import zh_CN from '../../src/locale/zh_CN';
27+
import enGB from '../../src/locale/en_GB';
28+
2729
import type { PickerBaseProps, PickerDateProps, PickerTimeProps } from '../../src/Picker';
2830
import type {
2931
PickerPanelBaseProps,
@@ -35,6 +37,8 @@ import {
3537
type RangePickerDateProps,
3638
type RangePickerTimeProps,
3739
} from '../../src/RangePicker';
40+
import dateFnsGenerateConfig from '../../src/generate/dateFns';
41+
import SinglePicker from '../../src/PickerInput/SinglePicker';
3842

3943
dayjs.locale('zh-cn');
4044
dayjs.extend(buddhistEra);
@@ -226,3 +230,17 @@ export function getDay(str: string): Dayjs {
226230
}
227231
throw new Error(`Format not match with: ${str}`);
228232
}
233+
// ===================================== Date fns =====================================
234+
const dateFnsLocale = {
235+
locale: enGB,
236+
generateConfig: dateFnsGenerateConfig,
237+
};
238+
239+
type DateFnsSinglePickerProps = Omit<PickerProps<Date>, 'locale' | 'generateConfig'> & React.RefAttributes<PickerRef>;
240+
241+
export const DateFnsSinglePicker = (props: DateFnsSinglePickerProps) => {
242+
return <SinglePicker
243+
{...dateFnsLocale}
244+
{...props}
245+
/>
246+
}

0 commit comments

Comments
 (0)