Ant Design DatePicker 禁用不可选日期与时间:`disabledDate` 与 `disabledTime` 完整实战指南
本文围绕 Ant Design(antd)DatePicker / RangePicker 组件中“禁用不可选日期与时间”这一高频业务场景展开:通过 disabledDate 与 disabledTime 两个回调精准控制可选范围,覆盖单日期选择、picker="month" 月份面板、以及 RangePicker 起止时间分别禁用的完整写法。文章以官方 Demo disabled-date 及其完整实现 disabled-date.tsx 为主线,并对照仓库中的类型定义与单元测试,帮助读者彻底掌握这套“日期 + 时间”双重禁用方案,直接落地到自己的业务表单中。
一、核心 API 语义:三件事先说清楚
在动手写代码前,先明确 Demo 描述中隐含的三个前提(原文见 disabled-date.md):
disabledDate用于禁用日期(天/月/年等单元格),它是 DatePicker、RangePicker、TimePicker 之外所有 picker 模式的通用能力;disabledTime用于禁用时间(时/分/秒),它只在日期选择器开启了showTime时才生效——文档明确指出 “disabledTimeonly works withshowTime”,没有showTime就不会渲染时间选择面板,禁用时间自然无从谈起;- 二者可以单独使用,也可以叠加使用(
disabledDate限制日期、disabledTime限制该日期的可选时刻),从而形成“某天可选但只能选某几个时段”这样的精细控制。
从 API 文档 index.en-US.md 可以看到 disabledDate 的完整签名:
disabledDate?: (currentDate: dayjs, info: { from?: dayjs; type: Picker }) => boolean
- 返回值语义:返回
true(或任意 truthy 值)表示当前单元格不可选,会被置灰并阻止点击;返回false表示可选。 currentDate:当前被判断的单元格对应的 dayjs 对象,是整个判断的核心输入。info对象(5.14.0起提供):其中type指当前面板模式(date/month/year/decade等),from在范围选择场景下指向已选中的另一端日期,可用于实现“结束不能早于开始”这类联动约束。
而 disabledTime 返回一个包含三个禁用函数(disabledHours、disabledMinutes、disabledSeconds)的对象,后文会逐一演示。
二、最小可用示例:禁止今天之前(含今天)
最经典的业务规则是“不允许选择过去的日期”。官方 Demo 的第一个场景正好演示了这一写法,其完整实现位于 disabled-date.tsx:
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
// Can not select days before today and today
return current && current < dayjs().endOf('day');
};
使用方式:
<DatePicker
format="YYYY-MM-DD HH:mm:ss"
disabledDate={disabledDate}
disabledTime={disabledDateTime}
showTime={{ defaultOpenValue: dayjs('00:00:00', 'HH:mm:ss') }}
/>
这里有两个值得展开的细节:
- 为什么用
endOf('day')而不是直接dayjs()? 注释明确写着“禁止今天及今天以前”。若写成current < dayjs(),由于比较的是毫秒时间戳,今天 0 点的单元格会小于“代码执行那一刻”的时间戳而被误伤;而current < dayjs().endOf('day')是把今天的结束时刻(23:59:59.999)作为边界,即今天整天也一并禁用。反之,若只想禁止“今天之前、今天仍可选”,应改为current && current < dayjs().startOf('day')。 - 为什么要判断
current本身? 面板中可能传入空值或边界值,current &&的短路写法避免了对空值做比较而产生误禁用。返回值需要兼容null的情况(此时应视为可选)。
仅禁止过去月份:切换 picker 模式
禁用逻辑与面板粒度强相关。disabledDate 的判断单位会随 picker 改变——当使用 picker="month" 时,currentDate 代表的是当月,因此判断边界也要换成月份粒度(同文件 disabled-date.tsx):
const disabledDateForMonth: RangePickerProps['disabledDate'] = (current) => {
// Can not select months before this month
return current && current < dayjs().startOf('month');
};
对比可看出:在日粒度下用 endOf('day'),在月粒度下用 startOf('month'),核心思路都是“把当前展示单元格(日/月)作为一个整体来判定是否早于允许的最早值”。
三、精确到时分秒:disabledTime + showTime
日期禁用到“天”往往不够。当业务要求“本周不可选”“9:00–17:00 之外不可约”时,就需要在 disabledDate 放行的日期内,进一步裁剪可选的时刻。此时开启 showTime 并配置 disabledTime(同文件 disabled-date.tsx):
const disabledDateTime = () => ({
disabledHours: () => range(0, 24).splice(4, 20),
disabledMinutes: () => range(30, 60),
disabledSeconds: () => [55, 56],
});
其中 range(start, end) 是官方 Demo 里自己封装的生成 [start, start+1, ..., end-1] 的辅助函数。我们拆开看每个字段做了什么:
| 返回值字段 | 含义 | 本示例效果 |
|---|---|---|
disabledHours: () => number[] |
返回被禁用的小时列表 | range(0, 24).splice(4, 20) = [4, 5, ..., 23],即只允许 0–3 点 |
disabledMinutes: () => number[] |
返回被禁用的分钟列表 | range(30, 60) = [30, 31, ..., 59],即前半小时可选 |
disabledSeconds: () => number[] |
返回被禁用的秒列表 | [55, 56],其余秒均可选 |
注意到 disabledDateTime 是一个无参函数,因为它对所有日期一视同仁。日期选择器 API 表格(index.en-US.md)中 disabledTime 的签名为 function(date)——如果你需要“不同日期可用的时间不同”,就可以接收 date 参数按日期分支处理。
配套设置
showTime.defaultOpenValue:由于很多时段被禁用,如果直接打开时间面板可能没有可聚焦的默认值,导致选中日期后时间部分为空。Demo 中通过showTime={{ defaultOpenValue: dayjs('00:00:00', 'HH:mm:ss') }}显式指定面板展开时默认选中的时间,同时外层format="YYYY-MM-DD HH:mm:ss"让输入框能展示完整的日期时间。该写法同样出现在官方 API 说明中被点名引用(showTime.defaultOpenValue一栏的示例链接正是#date-picker-demo-disabled-date)。
四、RangePicker:起止时间分别禁用
范围选择是 disabledDate/disabledTime 发挥最大价值的场景——起止两端往往需要不同的时间约束。先看纯日期版,只禁过去日期:
<RangePicker disabledDate={disabledDate} />
再看“起止时间分别禁用”的进阶版(disabled-date.tsx):
const disabledRangeTime: RangePickerProps['disabledTime'] = (_, type) => {
if (type === 'start') {
return {
disabledHours: () => range(0, 60).splice(4, 20),
disabledMinutes: () => range(30, 60),
disabledSeconds: () => [55, 56],
};
}
return {
disabledHours: () => range(0, 60).splice(20, 4),
disabledMinutes: () => range(0, 31),
disabledSeconds: () => [55, 56],
};
};
对应的组件写法:
<RangePicker
disabledDate={disabledDate}
disabledTime={disabledRangeTime}
showTime={{
hideDisabledOptions: true,
defaultOpenValue: [dayjs('00:00:00', 'HH:mm:ss'), dayjs('11:59:59', 'HH:mm:ss')],
}}
format="YYYY-MM-DD HH:mm:ss"
/>
与单日期版本的关键差异:
- 回调多了第二个参数
type。RangePicker 的disabledTime签名为function(date: dayjs, partial: 'start' | 'end', info: { from?: dayjs })(见 index.en-US.md),partial告诉你当前正在配置的是起点还是终点。info.from自5.17.0起提供,指向另一端已选日期,可用于实现“结束日当天只能选比开始时刻晚的时间”这类联动。 - 起止的策略在本例中是对称的:起点允许 0–3 点的早间时段,终点允许 20–23 点的晚间时段,配合外层
disabledDate(禁过去日期),模拟出“早出发 / 晚返回”的业务直觉。 showTime.hideDisabledOptions:置为true后,被禁用的时/分/秒选项会直接从下拉列表中隐藏而不是灰色展示,UI 更干净,适合禁用项很多的场景;保持默认false则灰显,能让用户感知存在但不可用的时段。defaultOpenValue变成了二元数组:分别对应起点和终点面板的默认打开时刻[00:00:00, 11:59:59],这正是 API 文档 index.en-US.md 中showTime.defaultOpenValue的 RangePicker 形态。
五、源码视角:这两个 Props 从哪来、如何生效
作为生成式组件的产物,DatePicker / RangePicker 的 Props 最终来自 @rc-component/picker 的 RcPickerProps / RcRangePickerProps。在 generatePicker/interface.ts 中可以看到:
export type PickerProps<DateType extends AnyObject = any> = InjectDefaultProps<
RcPickerProps<DateType>
>;
export type RangePickerProps<DateType extends AnyObject = any> = InjectDefaultProps<
RcRangePickerProps<DateType>
>;
disabledDate、disabledTime、showTime 等能力均由底层 @rc-component/picker 实现,antd 通过 InjectDefaultProps 在类型层面注入 locale、placement、variant、classNames/styles 等 antd 语义化封装,因此你在业务代码中通过 GetProps<typeof DatePicker.RangePicker> 取出的 Props 类型(Demo 第 7 行的 RangePickerProps)天然带全这些字段的精确签名与 dayjs 泛型推导。关于单元格禁用的具体交互(置灰、阻止点击、键盘导航跳过),都发生在该底层选择器包的日期面板内部,antd 层负责把回调透传下去。
这一行为的正确性在仓库测试中有直接印证。DatePicker.test.tsx 中就有一个与本文完全同构的用例:
const disabledDate = (current: any) => current && current < dayjs().endOf('day');
render(<DatePicker disabledDate={disabledDate} open />);
它用 endOf('day') 的判定方式构造禁用日期并渲染面板,验证日期格子的禁用与不可点选行为,说明“禁止今天及更早日期”是 antd 官方认可的标准写法,你可以放心在生产代码中复用。
六、API 速查与注意事项
参数速查
| 参数 | 作用 | 类型 | 可用组件 | 版本备注 |
|---|---|---|---|---|
disabledDate |
指定不可选择的日期(单元格粒度随 picker 变化) |
(currentDate: dayjs, info: { from?: dayjs, type: Picker }) => boolean |
DatePicker / RangePicker | info 参数自 5.14.0 提供 |
disabledTime |
指定不可选择的时间,须与 showTime 搭配 |
DatePicker:function(date);RangePicker:function(date: dayjs, partial: 'start' | 'end', info: { from?: dayjs }) |
DatePicker / RangePicker(开启 showTime 时) |
RangePicker 的 info.from 自 5.17.0 提供 |
showTime.hideDisabledOptions |
隐藏(true)或灰显(默认 false)被禁用的时分秒选项 |
boolean | 二者 | — |
showTime.defaultOpenValue |
打开时间面板时的默认选中时刻;RangePicker 传二元数组 | dayjs | [dayjs, dayjs] | 二者 | 取代已废弃的 showTime.defaultValue |
实践要点清单
- 边界值用粒度匹配的
startOf/endOf:禁“今天及以前”用current < dayjs().endOf('day');禁“本月及以前”用current < dayjs().startOf('month');不同picker粒度要换对应的比较单位。 disabledTime离不开showTime:不加showTime时传入disabledTime不会生效(无时间面板可操作)。- RangePicker 务必利用
partial: 'start' | 'end'区分两端,否则两端会套用同一套时间禁用规则;更复杂的“结束时间不能早于开始时间”联动可读取info.from。 - 配合
format与defaultOpenValue:一旦约束到时分秒,建议把format扩为"YYYY-MM-DD HH:mm:ss",并通过defaultOpenValue给时间面板一个合法默认值,避免“日期可选但时间无可选默认项”的空白态。 - 纯禁用需求的轻量替代:若只是禁止“某一天之前/之后”,
5.14.0起还可用minDate/maxDate(见 index.en-US.md);但当禁用规则是“非连续的若干天/特定星期几/排除节假日”这类任意逻辑时,函数式disabledDate仍是唯一通用的方案。 - 从完整示例起步:本文所有代码均取自可直接运行的官方 Demo disabled-date.tsx,它同时覆盖了单日期、月份面板、RangePicker 日期、RangePicker 日期+时间四种形态,是复刻到业务代码的最佳模板。配套的更多用法(时间选择、区间联动、禁止整组件)可进一步参考同目录下的 time.md、range-picker.md 与 disabled.md 等 Demo。
掌握 disabledDate 与 disabledTime 的组合用法后,无论是“仅可选未来 30 天”“工作日可选”“历史日期仅早班可约”还是“RangePicker 起止时间错峰”等真实业务约束,都可以用声明式回调在几分钟内稳定实现,而不必在提交前做二次表单校验来兜底。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00