☰
RSUITE DateRangePicker 日期时间格式自定义实战:format、showMeridiem 与 defaultCalendarValue 组合用法
2026/9/27 11:12:49 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

导读

RSUITE 的DateRangePicker组件默认以dd/MM/yyyy格式展示日期范围,但在真实业务中我们往往需要携带具体时刻、切换 12 小时制,甚至只选择时间段。本文以官方文档示例 format-date-time.md 为骨架,系统讲解如何通过format、showMeridiem、defaultCalendarValue、ranges等属性组合出「日期+时间范围」「纯时间范围」「12 小时制(AM/PM)」三类典型场景,并结合 DateRangePicker 源码 揭示format字符串是如何驱动日历面板、时间选择器与输入框行为的。读完本文,你将能根据自己的业务任意定制日期时间格式,并理解其背后的实现原理。

一、示例总览:三种典型时间格式

官方文档 format-date-time.md 给出了一个覆盖三种典型场景的完整示例:

import { DateRangePicker } from 'rsuite'; const App = () => ( <div className="field"> <p>Date Time Range</p> <DateRangePicker format="yyyy-MM-dd HH:mm:ss" defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> <p>Time Range</p> <DateRangePicker format="HH:mm:ss" ranges={[]} defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> <p>Meridiem format</p> <DateRangePicker format="hh:mm aa" showMeridiem defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> </div> ); ReactDOM.render(<App />, document.getElementById('root'));

三组示例分别对应:

场景format 取值关键属性
日期 + 时间范围yyyy-MM-dd HH:mm:ssdefaultCalendarValue
纯时间范围HH:mm:ssranges={[]}、defaultCalendarValue
12 小时制(Meridiem)hh:mm aashowMeridiem、defaultCalendarValue

三组示例都通过defaultCalendarValue预先指定日历面板的默认展示区间,保证打开弹层时前后两个日历月处于2022-02与2022-05,让示例效果稳定可复现。

二、认识 format:组件的“显示与行为”开关

format是DateRangePicker的核心属性之一。根据 官方 Props 文档:

  • 属性名:format
  • 类型:string
  • 默认值:'dd/MM/yyyy'
  • 作用:设置日期范围在输入框中渲染时的格式

在 DateRangePicker 源码 中,format的解析起点是:

const formatStr = format || locale?.shortDateFormat || 'yyyy-MM-dd'; const rangeFormatStr = `${formatStr}${character}${formatStr}`;

即:未显式传入format时,会回退到locale.shortDateFormat,最后兜底为yyyy-MM-dd;而输入框最终展示的字符串是「起始日期格式化结果 + 分隔符character+ 结束日期格式化结果」,character默认值为' ~ '(见同文件character = ' ~ '的默认参数解构)。

format使用的是类 date-fns 的令牌(token)语法,常见令牌如下:

令牌含义示例输出
yyyy四位数年份2022
MM两位数月份02
MMM/MMMM缩写 / 全称月份Feb/February
dd两位数日期01
HH24 小时制小时(00–23)14
hh12 小时制小时(01–12)02
mm分钟30
ss秒45
aaAM / PM 标记AM、PM

除英文字母令牌外,格式串中也可以嵌入任意文字,例如yyyy年MM月dd日,这一点在 format.md 示例 中直接使用。

format 决定面板形态:源码级原理

format不仅是显示格式,还直接决定了日历弹层“长什么样”。源码在 DateRangePicker.tsx 中通过useDateMode对格式串做模式判定:

const { mode, has } = useDateMode(formatStr); // Show only the calendar month panel. formatStr = 'yyyy-MM' const onlyShowMonth = mode === DateMode.Month; // Only show the time panel. formatStr = 'HH:mm:ss' const onlyShowTime = mode === DateMode.Time; // Allows two calendar panels to display the same month. const allowSameMonth = onlyShowMonth || showOneCalendar || onlyShowTime; // Default gap between two calendars, if `showOneCalendar` is set, the gap is 0 const calendarGap = allowSameMonth ? 0 : 1;

模式判定逻辑实现在 useDateMode.ts 与 formatCheck.ts 中:

  • shouldRenderTime(format):正则/([Hhms])/,只要格式串包含H、h、m、s中的任一字符即视为含时间;
  • shouldOnlyRenderTime(format):包含[Hhms]且不包含[YyMDd](如HH:mm:ss),判定为纯时间模式DateMode.Time;
  • shouldRenderDate(format):同时包含[Yy]、[ML]、[Dd],判定为日期模式DateMode.Date;
  • 日期与时间同时存在时判定为DateMode.DateTime。

由此可以理解本文示例的三种行为差异:

  • format="yyyy-MM-dd HH:mm:ss"→DateTime模式:同时渲染双月日历与时间选择器;
  • format="HH:mm:ss"→Time模式(onlyShowTime为 true):弹层只展示时间选择面板,不再渲染日历网格,这也是该示例需要配合ranges={[]}的原因——面板上只有时间可操作;
  • format="hh:mm aa"→ 同样是纯时间模式,但配合showMeridiem以 12 小时制呈现。

在Time模式下,两个日历面板允许展示同一个月(allowSameMonth为 true),calendarGap变为 0;而在普通日期模式下,前后两个日历默认间隔 1 个月(源码中getSafeCalendarDate的默认区间为「当月 + 下月」)。

时间模式下改变日期会保留时间

当格式同时包含日期与时间时,用户点击日期只会改变年月日,而不会重置时分秒。这一行为由 DateRangePicker.tsx 中的copyTime保证:

// The time should remain the same when the dates in the date range are changed. if ( has('time') && dateRange?.length && (eventName === 'changeDate' || eventName === 'changeMonth') ) { const startDate = copyTime({ from: getCalendarDatetime('start'), to: dateRange[0] }); const endDate = copyTime({ from: getCalendarDatetime('end'), to: dateRange.length === 1 ? addMonths(startDate, calendarGap) : dateRange[1] }); nextValue = [startDate, endDate]; }

即:日期变更事件(changeDate/changeMonth)发生时,从当前日历基准时间getCalendarDatetime('start'/'end')中取出时分秒,拷贝到新选中的日期上,从而保证「先选日期、后调时间」的交互符合预期。

三、场景一:日期 + 时间范围(Date Time Range)

<DateRangePicker format="yyyy-MM-dd HH:mm:ss" defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />

要点说明:

  1. format="yyyy-MM-dd HH:mm:ss"让输入框按「年-月-日 时:分:秒」显示,例如2022-02-01 00:00:00 ~ 2022-05-01 23:59:59;
  2. defaultCalendarValue的类型为[Date, Date],作用是设置日历面板的默认展示日期(而非输入框的值),源码中在getSafeCalendarDate({ value: value ?? defaultCalendarValue ?? null, allowSameMonth })处被消费(DateRangePicker.tsx)。当组件没有受控值或默认值时,弹层打开即定位到该区间;
  3. 用户可在日历上先后点击起始日期与结束日期完成范围选择,再通过面板内的时间选择器(时/分/秒下拉)微调具体时刻,最后点击 OK 确认。

需要区分的是:defaultCalendarValue只影响日历面板的初始展示月份,与defaultValue(非受控默认值)是两个不同概念,详见 官方 Props 表。

四、场景二:纯时间范围(Time Range)

<DateRangePicker format="HH:mm:ss" ranges={[]} defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />

要点说明:

  1. format="HH:mm:ss"由于不包含任何年/月/日令牌,被 formatCheck.ts 判定为纯时间模式,日历弹层只渲染时间选择面板;
  2. ranges={[]}清空预置快捷范围。ranges默认提供Today、Yesterday、Last 7 days三个快捷选项(见 官方 Props 表 中ranges的默认说明);纯时间场景下这些日期快捷项没有意义,因此置空;
  3. 时间选择器通过点击即可完成开始时间与结束时间的两次选择。测试用例中也验证了纯时间格式的行为——DateRangePicker.spec.tsx 中以format="hh:mm:ss"渲染组件后,通过设置起始时间的时/分/秒为 6:6:6 断言时间选择生效。

五、场景三:12 小时制(Meridiem)格式

<DateRangePicker format="hh:mm aa" showMeridiem defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />

要点说明:

  1. format="hh:mm aa"中hh表示 12 小时制小时(01–12),aa表示 AM/PM 标记,两者必须配合使用;
  2. showMeridiem是布尔属性,源码注释为「Meridiem format for 12-hour time」(DateRangePicker.tsx),它在时间选择面板中展示 AM/PM 切换项。注意源码中还存在已废弃的showMeridian属性,注释明确建议「UseshowMeridieminstead」;
  3. showMeridiem会被透传给日历组件(calendarProps中的showMeridiem),并参与时间选项的渲染(见 DateRangePicker.tsx)。

实际渲染效果类似02:00 AM ~ 05:00 PM。需要 24 小时制时使用HH:mm且不要设置showMeridiem。

六、与 format 强相关的配套属性

除了format本身,官方文档 中还有一批属性与日期时间格式配合使用,在定制格式时常被一并调整:

属性类型 / 默认值说明
characterstring,默认' ~ '两个日期之间的分隔符,例如设为' – '后展示为2022-02-01 – 2022-05-01
defaultCalendarValue[Date, Date]日历面板默认展示的日期区间
defaultValue[Date, Date]非受控模式下的默认选中值
value[Date, Date]受控模式下的当前值
editableboolean,默认true是否允许通过键盘在输入框内直接输入日期时间
placeholderstring输入框占位提示
showHeaderboolean,默认true是否在日历顶部展示格式化后的日期范围(v5.52.0 起)
rangesRange[]预置快捷范围,纯时间或纯月份场景通常置为[]

其中editable值得注意:DateRangePicker默认允许键盘直接录入日期时间(editable={true}),输入内容同样按formatStr解析校验;若希望禁止键盘输入、只允许点选,可设editable={false}。

更多 format 组合示例

format.md 还提供了大量可直接套用的组合,摘录如下:

<DateRangePicker format="MM/dd/yyyy" character=" – " /> <DateRangePicker format="dd.MM.yyyy" /> <DateRangePicker format="MMM dd, yyyy" /> <DateRangePicker format="MMMM dd, yyyy" /> <DateRangePicker format="yyyy年MM月dd日" /> <DateRangePicker format="MM/dd/yyyy HH:mm" /> <DateRangePicker format="MM/dd/yyyy hh:mm aa" showMeridiem /> <DateRangePicker format="MMM yyyy" caretAs={BsCalendar2MonthFill} ranges={[]} /> <DateRangePicker format="HH:mm:ss" caretAs={FaClock} ranges={[]} /> <DateRangePicker format="dd MMM yyyy hh:mm:ss aa" showMeridiem caretAs={FaCalendar} ranges={[]} />

其中format="MMM yyyy"仅含年与月,会被判定为DateMode.Month模式,弹层直接展示月份选择面板(onlyShowMonth);caretAs则用于替换输入框右侧的日历图标,与纯时间/纯月份场景搭配更语义化。

七、源码验证:格式与输入渲染

format还参与输入框尺寸的计算与值的渲染:

  • getInputHtmlSize 会按rangeFormatStr(或选中值经formatDate格式化后的完整字符串)的长度动态计算输入框 HTML 宽度,因此长格式(如yyyy-MM-dd HH:mm:ss)会自动获得更宽的输入框;
  • 输入框展示值由formatDate(startDate, formatStr)与formatDate(endDate, formatStr)拼接而成,formatDate来自useCustom('DateRangePicker', props)的国际化格式化函数;
  • 日历顶部的Header同样接收formatStr与character,将当前选中/悬停区间实时格式化展示(DateRangePicker.tsx)。

测试用例也验证了格式化渲染结果,例如 DateRangePicker.spec.tsx 中:

const template = 'MM/dd/yyyy hh:mm:ss'; render(<DateRangePicker value={value} format={template} />); expect(screen.getByRole('textbox')).to.have.value('11/11/2019 01:00:00 ~ 11/12/2019 01:00:00');

即输入框严格按起始值 + character(' ~ ') + 结束值的规则渲染,与 format-date-time.md 示例中的预期展示一致。

八、实践建议与小结

  1. 先定业务粒度,再写 format:只要日期 →yyyy-MM-dd类;日期+时刻 → 追加HH:mm或HH:mm:ss;只要时刻 → 纯时间格式并配ranges={[]};只要月份 →yyyy-MM或MMM yyyy;
  2. 12 小时制必须成对使用:hh+aa+showMeridiem,缺一不可;24 小时制使用HH且不设置showMeridiem;
  3. 注意默认值对象粒度:defaultCalendarValue是[Date, Date]形式的 Date 对象数组,传入的起始时刻(如00:00:00、23:59:59)会成为该侧日历的时间基准,配合copyTime机制在后续日期变更时被保留;
  4. 纯时间/纯月份场景记得清空ranges,避免出现语义不符的「Today / Yesterday」快捷项;
  5. 若希望展示更紧凑,可同时调整character分隔符(如' – '),该字符同样会出现在日历头部与输入框渲染结果中。

通过format+showMeridiem+defaultCalendarValue+ranges的组合,DateRangePicker足以覆盖绝大多数业务中的日期时间范围选择需求;而理解useDateMode对格式串的模式判定,能帮助你预判日历面板的最终形态,做到「改一行 format,面板随之自适应」。

  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载
上一篇:Zcash 6.20.0 与 zcashd 全节点:隐私共识实现、从源码构建与生命周期管理指南
下一篇:基于 Eleventy 的零配置博客模板:从本地构建到一键部署 Vercel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询