logoAnt Design

⌘ K
  • 디자인
  • 개발
  • 컴포넌트
  • 블로그
  • 자료
5.21.3
  • 为什么禁用日期这么难?
  • Why is it so hard to disable the date?
  • 封装 Form.Item 实现数组转对象
  • HOC Aggregate FieldItem
  • 行省略计算
  • Line Ellipsis Calculation
  • 📢 v4 维护周期截止
  • 📢 v4 surpassed maintenance period
  • Type Util
  • 一个构建的幽灵
  • A build ghost
  • 当 Ant Design 遇上 CSS 变量
  • Ant Design meets CSS Variables
  • API 기술 부채
  • 생동감 있는 Notification
  • 色彩模型与颜色选择器
  • Color Models and Color Picker
  • 主题拓展
  • Extends Theme
  • 虚拟表格来了!
  • Virtual Table is here!
  • Happy Work 테마
  • Happy Work Theme
  • 동적 스타일은 어디로 갔을까?
  • Suspense 引发的样式丢失问题
  • Suspense breaks styles
  • Bundle Size Optimization
  • 안녕, GitHub Actions
  • 所见即所得
  • To be what you see
  • 정적 메서드의 고통
  • SSR에서 정적 스타일 추출
  • SSR Static style export
  • 의존성 문제 해결
  • 贡献者开发维护指南
  • Contributor development maintenance guide
  • 转载-如何提交无法解答的问题
  • Repost: How to submit a riddle
  • 新的 Tooltip 对齐方式
  • Tooltip align update
  • Unnecessary Rerender
  • 如何成长为 Collaborator
  • How to Grow as a Collaborator
  • Funny Modal hook BUG
  • Modal hook 的有趣 BUG
  • about antd test library migration
  • antd 测试库迁移的那些事儿
  • Tree 的勾选传导
  • Tree's check conduction
  • getContainer 的一些变化
  • Some change on getContainer
  • Component-level CSS-in-JS

Why is it so hard to disable the date?

Resources

Ant Design Charts
Ant Design Pro
Ant Design Pro Components
Ant Design Mobile
Ant Design Mini
Ant Design Landing-Landing Templates
Scaffolds-Scaffold Market
Umi-React Application Framework
dumi-Component doc generator
qiankun-Micro-Frontends Framework
ahooks-React Hooks Library
Ant Motion-Motion Solution
China Mirror 🇨🇳

Community

Awesome Ant Design
Medium
Twitter
yuque logoAnt Design in YuQue
Ant Design in Zhihu
Experience Cloud Blog
seeconf logoSEE Conf-Experience Tech Conference
Work with Us

Help

GitHub
Change Log
FAQ
Bug Report
Issues
Discussions
StackOverflow
SegmentFault

Ant XTech logoMore Products

yuque logoYuQue-Document Collaboration Platform
AntV logoAntV-Data Visualization
Egg logoEgg-Enterprise Node.js Framework
Kitchen logoKitchen-Sketch Toolkit
Galacean logoGalacean-Interactive Graphics Solution
xtech logoAnt Financial Experience Tech
Theme Editor
Made with ❤ by
Ant Group and Ant Design Community
loading

In antd, there are many question about DatePicker. One is due to the commonality of date selection requirements, and the other is that there are various combinations of disabled selections for business requirements. Today, let's talk about the disabledDate API.

disableDate cannot control time

As its name suggests, disabledDate is used to disable dates. So when using DateTimePicker, the time part is not controlled by disabledDate. Instead, it needs to be controlled through the disabledTime method. This seems a bit counterintuitive. Why do antd need two APIs to manage it?

How to determine if a date can be selected?

In terms of intuition, we only need to execute disabledDate once for a date to determine if it is disabled. However, if we switch the panel to the month panel, how do we know if the current month is selectable? We must execute disabledDate for each date in that month to determine if there are selectable dates in that month, so that month can be selected.

This logic seems fine for now. A month has about 30 days, and there are 12 months in the month panel. In the worst case, we only need to iterate 365 times to know that 12 months are not selectable. But as the panel switches to years and decades, the number of iterations required will increase exponentially, leading to serious performance issues (#39991)

So after the DatePicker refactoring, disabledDate provides an additional parameter info.type, which tells you which Panel the provided date object comes from. This allows developers to provide disabled information based on the Panel, thus avoiding the terrifying call loop.

But as a fallback, DatePicker will call disabledDate for the first and last days of the current Panel unit. This ensures that common range disable scenarios are still met.

disabledTime

Back to time disable, this is the same problem. If we use disabledDate to disable time dimensions, then whether a day is selectable in DateTimePicker, we need to check each second of that day with disabledDate. In the worst case, whether a day is selectable needs to be checked 86400 times. The Date Panel needs to execute ~2 million times. Obviously, this is unacceptable.

So for the time dimension, we provide the disabledTime method. This method requires more granular time disable information than disabledDate:

type DisabledTime = (now: Dayjs) => {
disabledHours?: () => number[];
disabledMinutes?: (selectedHour: number) => number[];
disabledSeconds?: (selectedHour: number, selectedMinute: number) => number[];
disabledMilliseconds?: (
selectedHour: number,
selectedMinute: number,
selectedSecond: number,
) => number[];
};

(Each unit of the time selection panel is equivalent to the Panel of the date panel, and the latter infers the current disabled unit from the information of the former unit)

Some examples

After understanding the context, we will find that disabledDate and disabledTime are designed to be reasonable, but they are somewhat low-level. It is more troublesome to use them in business. Let's look at a few examples (of course, you need to consider encapsulating them through HOC in business):

Working hours

Temporarily ignore the situation of holidays and choose 9:00 ~ 17:00 on working days as the selectable time:

const disabledDate = (date, info) => {
if (info.type === 'date') {
return date.day() === 0 || date.day() === 6;
}
return false;
};
const disabledTime = () => ({
disabledHours: () => {
return Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour < 9 || hour > 17);
},
});

Date and time range

In DatePicker, there are minDate and maxDate to limit the date selection range. But they only limit to date range. Now, suppose we have a scenario that requires a date range selection with time, such as 2024-01-01 09:00:00 ~ 2024-01-02 17:00:00, then we can do this:

const disabledDate = (date, info) => {
if (info.type === 'date') {
return date.isBefore('2024-01-01', 'day') || date.isAfter('2024-01-02', 'day');
}
return !date.isSame('2024-01-01', info.type);
};
const disabledTime = (date) => {
if (date.isSame('2024-01-01', 'day')) {
return {
disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour < 9),
};
}
if (date.isSame('2024-01-02', 'day')) {
return {
disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter((hour) => hour > 17),
};
}
// Only need to consider the start and end time
// the range itself has been disabled by `disabledDate`
return {};
};

Summary

Through disabledDate and disabledTime, we can control the date and time more finely to meet different business requirements. With the examples above, I believe you have a deeper understanding of these two APIs. In actual business, you can combine these two APIs to achieve more functions.