FullCalendar自定义时间格式:从12小时制到农历显示的实现
引言:时间格式的痛点与解决方案
在开发日程管理应用时,你是否曾遇到过时间显示不符合用户习惯的问题?例如,国际用户需要12小时制带AM/PM标识,国内用户可能需要农历显示,而企业用户则可能需要精确到秒的时间格式。FullCalendar作为一款功能强大的JavaScript日程库,提供了灵活的时间格式化机制,但许多开发者在面对复杂需求时仍感到困惑。
本文将系统讲解FullCalendar的时间格式化体系,从基础的12/24小时制切换,到高级的农历显示,帮助你掌握从简单配置到深度定制的全流程。读完本文后,你将能够:
- 熟练配置内置时间格式选项
- 自定义事件时间、槽位标签和列标题的显示格式
- 集成第三方库实现农历等复杂历法显示
- 解决时区转换和本地化显示的常见问题
FullCalendar时间格式化基础
核心格式化选项
FullCalendar提供了多个关键选项用于控制时间显示,这些选项在packages/core/src/options.ts中定义:
// 核心时间格式化选项
{
slotLabelFormat: identity as Identity<FormatterInput | FormatterInput[]>,
eventTimeFormat: createFormatter,
columnHeaderFormat: { weekday: 'short', month: 'numeric', day: 'numeric' }
}
这些选项接受两种类型的输入:
- 字符串格式(如
'HH:mm') - 对象格式(如
{ hour: '2-digit', minute: '2-digit' })
12小时制与24小时制切换
最常见的需求是切换12小时制与24小时制显示,这可以通过eventTimeFormat选项实现:
// 24小时制配置(默认)
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false // 关键参数:false为24小时制,true为12小时制
}
// 12小时制配置
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: true // 显示AM/PM
}
注意:在不同的本地化环境中,
hour12的默认值可能不同。美国英语 locale 默认使用12小时制,而大多数其他 locale 默认使用24小时制。
常用时间格式字符串速查表
| 格式字符串 | 描述 | 示例 |
|---|---|---|
HH:mm | 24小时制,带分钟 | 14:30 |
h:mm a | 12小时制,带AM/PM | 2:30 PM |
HH:mm:ss | 带秒的24小时制 | 14:30:45 |
yyyy-MM-dd | 年-月-日 | 2023-10-05 |
MMM d, yyyy | 缩写月份和日期 | Oct 5, 2023 |
高级时间格式定制
按视图类型定制格式
不同的视图(月视图、周视图、日视图)可能需要不同的时间格式,可以通过对象形式为特定视图配置:
slotLabelFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false
},
views: {
timeGridDay: {
slotLabelFormat: { // 仅应用于日视图
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}
},
dayGridMonth: {
columnHeaderFormat: { // 月视图的列标题格式
weekday: 'long', // 完整星期名
month: 'short', // 缩写月份
day: 'numeric' // 日期数字
}
}
}
事件时间格式化实战
在tests/src/legacy/eventTimeFormat.ts中可以找到事件时间格式化的测试案例,以下是实际应用示例:
// 基础事件时间格式
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false
}
// 带秒的高精度格式
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}
// 字符串简写形式
eventTimeFormat: 'HH:mm:ss' // 等同于上面的对象格式
槽位标签和列标题格式
除了事件时间,还可以自定义时间槽标签和列标题的格式:
// 槽位标签格式(左侧时间轴)
slotLabelFormat: {
hour: '2-digit',
minute: '2-digit',
omitZeroMinute: true, // 当分钟为0时省略
meridiem: 'short' // 显示AM/PM(仅12小时制)
},
// 列标题格式(日历顶部日期)
columnHeaderFormat: {
weekday: 'short', // 星期缩写(如"周一")
month: 'numeric', // 数字月份
day: 'numeric', // 日期
daySuffix: 'short' // 日期后缀(如"1st"、"2nd")
}
本地化与时区处理
多语言支持
FullCalendar通过locale选项支持多语言显示,需要引入相应的语言包:
import zhCN from '@fullcalendar/core/locales/zh-cn';
const calendar = new FullCalendar.Calendar(el, {
locale: zhCN, // 设置为中文
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false // 中文环境默认使用24小时制
}
});
时区配置
时区处理是时间显示的重要部分,在tests/src/datelib/main.ts中可以看到相关测试配置:
// 时区配置示例
{
timeZone: 'UTC', // 使用UTC时区
// timeZone: 'local', // 使用本地时区
// timeZone: 'Asia/Shanghai' // 使用特定时区
}
当切换时区时,FullCalendar会自动调整所有时间显示:
// 动态切换时区
calendar.setOption('timeZone', 'America/New_York');
时区转换示例
以下是一个完整的时区转换示例,展示同一事件在不同时区的显示效果:
document.addEventListener('DOMContentLoaded', function() {
const calendarEl = document.getElementById('calendar');
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridDay',
events: [
{
title: '跨时区会议',
start: '2023-10-05T12:00:00', // 事件原始时间(ISO格式)
end: '2023-10-05T13:00:00',
timeZone: 'UTC' // 事件所在时区
}
],
timeZone: 'Asia/Shanghai', // 初始显示时区
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false
}
});
calendar.render();
// 时区切换按钮
document.getElementById('tz-utc').addEventListener('click', () => {
calendar.setOption('timeZone', 'UTC');
});
document.getElementById('tz-shanghai').addEventListener('click', () => {
calendar.setOption('timeZone', 'Asia/Shanghai');
});
document.getElementById('tz-newyork').addEventListener('click', () => {
calendar.setOption('timeZone', 'America/New_York');
});
});
高级定制:实现农历显示
集成农历库
要实现农历显示,需要集成第三方农历库,如lunar-javascript。以下是实现方案:
- 安装农历库:
npm install lunar-javascript
- 创建自定义格式化函数:
import { Solar, Lunar } from 'lunar-javascript';
// 自定义日期格式化函数
function formatWithLunar(date) {
const solar = Solar.fromDate(date);
const lunar = solar.getLunar();
// 公历日期
const solarStr = solar.toYmd();
// 农历日期
const lunarStr = `${lunar.getYearInChinese()}年${lunar.getMonthInChinese()}${lunar.getDayInChinese()}`;
// 结合显示
return `${solarStr} (${lunarStr}${lunar.isLeap() ? '闰' : ''})`;
}
自定义列标题组件
通过columnHeaderContent回调自定义列标题,集成农历显示:
columnHeaderContent: function(info) {
const date = info.date;
const solar = Solar.fromDate(date);
const lunar = solar.getLunar();
// 返回HTML元素
const div = document.createElement('div');
div.innerHTML = `
<div class="solar-date">${date.getDate()}</div>
<div class="lunar-date">${lunar.getDayInChinese()}</div>
${lunar.isFestive() ? `<div class="festival">${lunar.getFestive()}</div>` : ''}
`;
return div;
}
自定义事件时间显示
通过eventContent回调自定义事件时间显示,加入农历信息:
eventContent: function(info) {
const start = info.event.start;
const end = info.event.end;
// 格式化公历时间
const timeText = info.timeText;
// 计算农历时间
const lunarStart = Solar.fromDate(start).getLunar();
const lunarTimeText = `农历${lunarStart.getMonthInChinese()}${lunarStart.getDayInChinese()}`;
// 返回自定义内容
return {
html: `
<div class="fc-title">${info.event.title}</div>
<div class="fc-time">${timeText} (${lunarTimeText})</div>
`
};
}
农历样式美化
添加CSS样式美化农历显示效果:
/* 列标题农历样式 */
.fc-col-header-cell-cushion {
display: flex;
flex-direction: column;
}
.lunar-date {
font-size: 12px;
color: #666;
}
.festival {
font-size: 10px;
color: #ff4d4f;
}
/* 事件农历样式 */
.fc-event .fc-time {
font-size: 12px;
}
常见问题与解决方案
格式不生效问题排查
如果时间格式设置不生效,可以按以下步骤排查:
- 检查是否使用了正确的选项名称(如
eventTimeFormat而非eventDateFormat) - 确认格式对象的属性是否正确(参考Intl.DateTimeFormat文档)
- 检查是否有视图特定的格式覆盖了全局设置
- 验证是否正确引入了相关依赖和本地化文件
性能优化
当处理大量事件或复杂格式化时,可能需要优化性能:
// 使用缓存避免重复计算
const formatCache = new Map();
function cachedLunarFormat(date) {
const key = date.toISOString();
if (formatCache.has(key)) {
return formatCache.get(key);
}
// 计算农历格式
const result = formatWithLunar(date);
formatCache.set(key, result);
// 设置缓存过期(24小时)
setTimeout(() => formatCache.delete(key), 86400000);
return result;
}
完整示例代码
以下是集成农历显示的完整日历配置示例:
document.addEventListener('DOMContentLoaded', function() {
const calendarEl = document.getElementById('calendar');
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false
},
columnHeaderContent: function(info) {
// 自定义列标题,显示农历
const date = info.date;
const solar = Solar.fromDate(date);
const lunar = solar.getLunar();
const div = document.createElement('div');
div.className = 'lunar-header';
div.innerHTML = `
<div class="solar">${date.getDate()}</div>
<div class="lunar">${lunar.getDayInChinese()}</div>
${lunar.isFestive() ? `<div class="festival">${lunar.getFestive()}</div>` : ''}
`;
return div;
},
eventContent: function(info) {
// 事件内容自定义
const start = info.event.start;
const lunarStart = Solar.fromDate(start).getLunar();
return {
html: `
<div class="event-title">${info.event.title}</div>
<div class="event-time">${info.timeText}</div>
<div class="event-lunar">农历${lunarStart.getMonthInChinese()}${lunarStart.getDayInChinese()}</div>
`
};
},
events: [
{
title: '农历新年活动',
start: '2023-01-22',
end: '2023-01-24'
},
// 更多事件...
]
});
calendar.render();
});
总结与展望
本文详细介绍了FullCalendar时间格式自定义的各个方面,从基础的12/24小时制切换,到高级的农历显示实现。我们学习了如何利用eventTimeFormat、slotLabelFormat和columnHeaderFormat等选项控制时间显示,以及如何通过locale和timeZone选项处理本地化和时区问题。
通过第三方库的集成,我们实现了农历等复杂历法的显示,这展示了FullCalendar的灵活性和可扩展性。未来,随着国际化需求的增加,FullCalendar可能会提供更直接的多历法支持,但目前通过本文介绍的方法,已经可以满足大多数定制需求。
最后,建议在实际开发中:
- 根据用户群体选择合适的默认时间格式
- 提供时区和历法切换选项,增强用户体验
- 注意性能优化,特别是在处理复杂格式化时
- 充分测试不同浏览器和设备上的显示效果
希望本文能帮助你更好地掌握FullCalendar的时间格式化技巧,打造更符合用户需求的日程应用。
附录:常用格式化选项速查表
| 选项 | 作用 | 示例值 |
|---|---|---|
eventTimeFormat | 事件时间格式 | { hour: '2-digit', minute: '2-digit' } |
slotLabelFormat | 槽位标签格式 | 'HH:mm' |
columnHeaderFormat | 列标题格式 | { weekday: 'short', day: 'numeric' } |
locale | 本地化设置 | 'zh-cn' |
timeZone | 时区设置 | 'Asia/Shanghai' |
displayEventEnd | 是否显示结束时间 | true |
allDayText | "全天"文本 | "全天" |
firstDay | 每周第一天 | 1(周一) |
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



