使用FullCalendar基于rrule字符串生成带时长日历的时间异常问题
问题:FullCalendar重复事件时间显示异常
我需要基于以下三个变量构建日历:
dtstart = '20240820T170000';dtend = '20240820T190000';rrule = 'FREQ=WEEKLY;UNTIL=20240917T235959Z;BYDAY=TU;WKST=SU';
我编写了如下代码:
<!DOCTYPE html> <html> <head> <link href='https://unpkg.com/fullcalendar@5.11.5/main.min.css' rel='stylesheet' /> <script src='https://unpkg.com/fullcalendar@5.11.5/main.min.js'></script> <script src='https://cdn.jsdelivr.net/npm/rrule@2.6.4/dist/es5/rrule.min.js'></script> <script src='https://cdn.jsdelivr.net/npm/@fullcalendar/rrule@5.11.5/main.global.min.js'></script> <script> document.addEventListener('DOMContentLoaded', function () { var calendarEl = document.getElementById('calendar'); // Event details var dtstart = '20240820T170000'; var dtend = '20240820T190000'; var rrule = 'FREQ=WEEKLY;UNTIL=20240917T235959Z;BYDAY=TU;WKST=SU'; // Function to calculate duration from DTSTART and DTEND function calculateDuration(dtstart, dtend) { var start = new Date(dtstart); var end = new Date(dtend); var durationInMs = end - start; var durationInHours = durationInMs / (1000 * 60 * 60); return durationInHours + ':00'; } var duration = calculateDuration(dtstart, dtend); var calendarConfig = { firstDay: 1, headerToolbar: { right: 'dayGridMonth,timeGridWeek,timeGridDay', center: 'title', left: 'prevYear,prev,next,nextYear' }, initialDate: dtstart, events: [] }; var rruleString = 'DTSTART:' + dtstart + '\nRRULE:' + rrule; calendarConfig.events.push({ title: '{{ view.field.title.original_value }}', rrule: rruleString, duration: duration // Use calculated duration }); var calendar = new FullCalendar.Calendar(calendarEl, calendarConfig); calendar.render(); }); </script> </head> <body> <div id='calendar'></div> </body> </html>
目前日历已正确识别事件的日期,但事件的时间显示异常:
日期显示正常👍:
时间显示异常👎:
请问这是什么原因?
原因及解决方法
核心问题1:时区不匹配
你的dtstart是不带时区标识的本地时间(20240820T170000),但rrule中的UNTIL参数带了Z后缀(表示UTC时区)。FullCalendar解析时会默认把无时区的DTSTART也当成UTC时间处理,导致本地显示的时间和预期出现偏移。
核心问题2:Duration格式错误
FullCalendar要求duration属性使用ISO 8601时长格式(比如PT2H表示2小时),但你当前返回的是2:00这种自定义格式,无法被正确解析,进而导致事件时间计算错误。
修复方案
方案一:统一时区+修正Duration格式
- 给
dtstart添加时区标识(比如你的本地时区是东八区,就写成20240820T170000+08:00),同时把rrule中的UNTIL改成对应时区的时间(去掉Z,写成20240917T235959+08:00),保证时区统一。 - 修改
calculateDuration函数,返回ISO 8601格式的时长:
function calculateDuration(dtstart, dtend) { var start = new Date(dtstart); var end = new Date(dtend); var durationInMs = end - start; var hours = Math.floor(durationInMs / (1000 * 60 * 60)); var minutes = Math.floor((durationInMs % (1000 * 60 * 60)) / (1000 * 60)); return `PT${hours}H${minutes}M`; }
方案二:使用RRule对象替代字符串(更推荐)
直接用rrule.js创建规则对象,避免手动拼接字符串的时区和格式问题:
// 替换原事件添加的代码 var rule = new RRule({ freq: RRule.WEEKLY, until: new Date('2024-09-17T23:59:59'), byweekday: [RRule.TU], wkst: RRule.SU, dtstart: new Date(dtstart) }); calendarConfig.events.push({ title: '{{ view.field.title.original_value }}', rrule: rule, duration: 'PT2H' // 直接指定2小时的ISO时长 });
内容的提问来源于stack exchange,提问作者VasyOK
相关产品推荐
相关产品推荐

