Use just like the regular DatePicker. Currently only uses a fixed locale.
Created
January 3, 2020 12:22
-
-
Save julianwachholz/abec7b951508cce1b1e621b6afb65f70 to your computer and use it in GitHub Desktop.
Ant Design <DatePicker /> with native Date and date-fns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import generatePicker from "antd/lib/date-picker/generatePicker"; | |
import { | |
addDays, | |
addMonths, | |
addYears, | |
format, | |
getWeek, | |
isAfter, | |
isValid, | |
parse, | |
setDate, | |
setHours, | |
setMinutes, | |
setMonth, | |
setSeconds, | |
setYear | |
} from "date-fns"; | |
import { enUS } from "date-fns/locale"; | |
import { GenerateConfig } from "rc-picker/lib/generate"; | |
const generateConfig: GenerateConfig<Date> = { | |
getNow: () => new Date(), | |
getWeekDay: date => date.getDay(), | |
getYear: date => date.getFullYear(), | |
getMonth: date => date.getMonth(), | |
getDate: date => date.getDate(), | |
getHour: date => date.getHours(), | |
getMinute: date => date.getMinutes(), | |
getSecond: date => date.getSeconds(), | |
addYear: (date, diff) => addYears(date, diff), | |
addMonth: (date, diff) => addMonths(date, diff), | |
addDate: (date, diff) => addDays(date, diff), | |
setYear: (date, year) => setYear(date, year), | |
setMonth: (date, month) => setMonth(date, month), | |
setDate: (date, num) => setDate(date, num), | |
setHour: (date, hour) => setHours(date, hour), | |
setMinute: (date, minute) => setMinutes(date, minute), | |
setSecond: (date, second) => setSeconds(date, second), | |
isAfter: (date1, date2) => isAfter(date1, date2), | |
isValidate: date => isValid(date), | |
locale: { | |
getWeekFirstDay: locale => 1, | |
getWeek: (locale, date) => getWeek(date), | |
getShortWeekDays: locale => { | |
const d = Array.from({ length: 7 }).map((_, day) => { | |
console.info("localize day ", day); | |
return enUS.localize.day(day, { width: "abbreviated" }); | |
}); | |
console.log("days", d); | |
return d; | |
}, | |
getShortMonths: locale => { | |
const m = Array.from({ length: 12 }).map((_, month) => | |
enUS.localize.month(month, { width: "abbreviated" }) | |
); | |
console.log("months", m); | |
return m; | |
}, | |
format: (locale, date, fmt) => { | |
fmt = fmt.replace("YYYY", "yyyy"); | |
fmt = fmt.replace("DD", "dd"); | |
return format(date, fmt, { locale: enUS }); | |
}, | |
parse: (locale, text, formats) => { | |
const fmt = formats[0].toLowerCase(); | |
return parse(text, fmt, new Date()); | |
} | |
} | |
}; | |
const DatePicker = generatePicker<Date>(generateConfig); | |
export default DatePicker; |
There are switching to DayJS with antd v5 - maybe that will solve all the problems.
ant-design/ant-design#33862
@thomastvedt For some reason your solution made my bundle grow by nearly 1MB even though I only added 2 languages.
It seems that dateFnsGenerateConfig is to blame.
The solutions above have a serious drawback - when entering an invalid date (for example, if you type a space in input field), the DatePicker crashes with the entire app.
We can fix this by referencing antd implementation: https://github.com/react-component/picker/blob/master/src/generate/dateFns.ts.
We can also modify the locale field so that the picker explicitly works with a specific locale:
import generatePicker from 'antd/lib/date-picker/generatePicker'
import type { GenerateConfig } from 'rc-picker/lib/generate'
import config from 'rc-picker/lib/generate/dateFns'
import {
isValid,
getWeek,
startOfWeek,
format as formatDate,
parse as parseDate
} from 'date-fns'
import { ru } from 'date-fns/locale'
const localeParse = (format: string) => {
return format
.replace(/Y/g, 'y')
.replace(/D/g, 'd')
.replace(/gggg/, 'yyyy')
.replace(/g/g, 'G')
.replace(/([Ww])o/g, 'wo')
}
const locale: GenerateConfig<Date>['locale'] = {
getWeekFirstDay: () => {
const clone = ru
return clone.options?.weekStartsOn ?? 1
},
getWeekFirstDate: (locale, date) => {
return startOfWeek(date, { locale: ru })
},
getWeek: (locale, date) => {
return getWeek(date, { locale: ru })
},
getShortWeekDays: () => {
const clone = ru
return Array.from({ length: 7 }).map((_, i) =>
clone.localize?.day(i, { width: 'short' })
)
},
getShortMonths: () => {
const clone = ru
return Array.from({ length: 12 }).map((_, i) =>
clone.localize?.month(i, { width: 'abbreviated' })
)
},
format: (locale, date, format) => {
if (!isValid(date)) {
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
return null as any
}
return formatDate(date, localeParse(format), {
locale: ru
})
},
parse: (locale, text, formats) => {
for (let i = 0; i < formats.length; i += 1) {
const format = localeParse(formats[i])
const formatText = text
const date = parseDate(formatText, format, new Date(), {
locale: ru
})
if (isValid(date)) {
return date
}
}
return null
}
}
export const DatePicker = generatePicker<Date>({ ...config, locale })
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, thanks for this 🙏 Did you ever make one with locale switchable on runtime?
Is there no way to pass locale dynamically to ant.design DatePicker on runtime?
dateFnsLocale.ts: