javascriptangularfullcalendarfullcalendar-5rrule

Full calendar doesn't display proper end time in week and day view in angular


I'm using full calendar v5 in angular https://fullcalendar.io/docs/v5/displayEventTime. In this calendar end time is not displayed but i'm passing end time also and in week view and day view end time is not extended properly if it is a 2 hour event it is not positioned properly it seems like all the events and of 1 hours.

export class eventComponent implements OnInit {

 @ViewChild('calendar') calendarComponent: FullCalendarComponent; 

  calendarOptions: CalendarOptions = {
    height:650,
    initialView: "timeGridWeek",
    scrollTime: this.currentdateTime,
  };

  ngOnInit() {
   loadCalendar()
  }

      loadCalendar(){ 
          let _self=this;
          this.calendarEvents=[];
          this.calendarOptions = {
            initialView: 'timeGridWeek',
            dateClick: this.onDateClick.bind(this),
            events: function(fetchInfo, successCallback, failureCallback) { 
              _self.Service.getEvent(fetchInfo.startStr,fetchInfo.endStr,400).subscribe((res) => {
                if(res?.length>0)
                {
                  _self.calendarEvents=res; 
                  _self.lstEvents = _self.calendarEvents.map(x => {
                   let utcStarttime=new Date(x.when.start_time * 1000).toString();
                   let utcEndtime=new Date(x.when.end_time * 1000).toString();
                   if(x?.recurrence?.rrule[0] && x?.recurrence?.rrule[0]!=undefined)
                   {
                   return {
                     ...x,
                    start: moment(utcStarttime).utc().format('YYYY-MM-DDTHH:mm:ss.sssZ'), 
                     startStr:moment(utcStarttime).utc().format('YYYY-MM-DDTHH:mm:ss.sssZ'),
                     endStr:moment(utcEndtime).utc().format('YYYY-MM-DDTHH:mm:ss.sssZ'),
                     end:moment(utcEndtime).utc().format('YYYY-MM-DDTHH:mm:ss.sssZ'),
                     alldays:false,
                     rrule: 'DTSTART:'+moment(utcStarttime).utc().format('YYYYMMDDTHHmmss[Z]')+'\n'+x?.recurrence?.rrule[0],
                   };
                   }
                   else
                   {
                     return {
                       ...x,
                       start: moment(utcStarttime).format('YYYY-MM-DDTHH:mm:ss.sssZ'), 
                       startStr:moment(utcStarttime).format('YYYY-MM-DDTHH:mm:ss.sssZ'),
                       endStr:moment(utcEndtime).format('YYYY-MM-DDTHH:mm:ss.sssZ'),
                       end: moment(utcStarttime).format('YYYY-MM-DDTHH:mm:ss.sssZ'), 
                       alldays:false,
                     };
                   }
                  });
                  successCallback(_self.lstEvents);
                }
                else
                {
                  successCallback(_self.lstEvents);
                }
            });
            },
            eventClick: this.handleEventClick.bind(this),
            headerToolbar: {
              left: 'prev,next today',
              center: 'title',
              right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
            },
            dayMaxEvents: 3,
            allDaySlot: false,
            weekends: true,
            editable: true,
            selectable: true,
            selectMirror: true,
            displayEventTime:true,
            displayEventEnd: true,
            height: 650,
            eventTimeFormat: { 
              hour: '2-digit',
              minute: '2-digit',
              hour12: true
            },
            plugins: [rrulePlugin,dayGridPlugin,timeGridPlugin, listPlugin,interactionPlugin],
            scrollTime: this.currentdateTime,
          };
      }

enter image description here

Please suggest some solution to fix this issue.

Response:
{
"id":"457457457457",
"object":"event",
"title":"test event",
"description":"",
"read_only":true,
"when":{
"start_time":1687183200,
"end_time":1687186800,
"object":"timespan"
},
"busy":true,
"status":"confirmed",
"recurrence":{
"rrule":[
"RRULE:FREQ=DAILY;UNTIL=20230625T140000Z;INTERVAL=1"
],
"timezone":"Asia/Calcutta"
},
"original_start_time":null,
"reminders":{
"reminder_minutes":15,
"reminder_method":"popup"
}
},

using this package:

    "@fullcalendar/angular": "^5.4.0",
    "@fullcalendar/core": "^5.4.0",
    "@fullcalendar/daygrid": "^5.4.0",
    "@fullcalendar/interaction": "^5.4.0",
    "@fullcalendar/list": "^5.4.0",
    "@fullcalendar/rrule": "^5.4.0",
    "@fullcalendar/timegrid": "^5.4.0",

Updated Cases:

I tried to pass this as a start time 1687894200 (28th June 1:00 AM) and end time 1690408800 (Thursday 27th July 3:30 AM)

  1. It is still displayed as 1 hour event only but it is 2:30 hrs event.

  2. I passed this rule RRULE:FREQ=WEEKLY;UNTIL=20230725T193000;BYDAY=TU,WE,TH,FR,SA,SU events are diplayed for monday also but tuesday it is not, Events should not display for Monday only showing event

pls check with this data :

var _self = {};
_self.calendarEvents = [];

document.addEventListener("DOMContentLoaded", function () {
  var calendarEl = document.getElementById("calendar");

  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: "timeGridWeek",
    //dateClick: this.onDateClick.bind(this),
    events: function (fetchInfo, successCallback, failureCallback) {
      var res = [
        {
          id: "457457457457",
          object: "event",
          title: "test event",
          description: "",
          read_only: true,
          when: {
            start_time: 1687894200,
            end_time: 1690408800,
            object: "timespan"
          },
          busy: true,
          status: "confirmed",
          recurrence: {
            rrule: ["RRULE:FREQ=WEEKLY;UNTIL=20230725T193000;BYDAY=TU,WE,TH,FR,SA,SU"],
            timezone: "Asia/Calcutta"
          },
          original_start_time: null,
          reminders: {
            reminder_minutes: 15,
            reminder_method: "popup"
          }
        }
      ];
      if (res?.length > 0) {
        _self.calendarEvents = res;
        _self.lstEvents = _self.calendarEvents.map((x) => {
          let utcStarttime = new Date(x.when.start_time * 1000).toString();
          console.log ("utcStarttime:" + utcStarttime);
          let utcEndtime = new Date(x.when.end_time * 1000).toString();
          console.log ("utcEndtime:" + utcEndtime);
          if (x?.recurrence?.rrule[0] && x?.recurrence?.rrule[0] != undefined) {
            return {
              ...x,
              start: moment(utcStarttime)
                .utc()
                .format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              startStr: moment(utcStarttime)
                .utc()
                .format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              endStr: moment(utcEndtime)
                .utc()
                .format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              end: moment(utcEndtime).utc().format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              alldays: false,
              rrule:
                "DTSTART:" +
                moment(utcStarttime).utc().format("YYYYMMDDTHHmmss[Z]") +
                "\n" +
                x?.recurrence?.rrule[0]
            };
          } else {
            return {
              ...x,
              start: moment(utcStarttime).format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              startStr: moment(utcStarttime).format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              endStr: moment(utcEndtime).format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              end: moment(utcStarttime).format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              alldays: false
            };
          }
        });
        console.log(JSON.stringify(_self.lstEvents));
        successCallback(_self.lstEvents);
      } else {
        //successCallback(_self.lstEvents);
      }
    },
    //eventClick: this.handleEventClick.bind(this),
    headerToolbar: {
      left: "prev,next today",
      center: "title",
      right: "dayGridMonth,timeGridWeek,timeGridDay,listWeek"
    },
    dayMaxEvents: 3,
    allDaySlot: false,
    weekends: true,
    editable: true,
    selectable: true,
    selectMirror: true,
    displayEventTime: true,
    displayEventEnd: true,
    height: 650,
    eventTimeFormat: {
      hour: "2-digit",
      minute: "2-digit",
      hour12: true
    },
    scrollTime: this.currentdateTime
  });

  calendar.render();
});

enter image description here

enter image description here


Solution

  • Firstly, regarding the duration of your events:

    As far as I can see, end is ignored when using rrule, because the end date is specified in the rrule string. Therefore it will not take the end time and work out the duration from that property, either.

    As per https://fullcalendar.io/docs/v5/rrule-plugin you must specify a duration instead for the events. The documentation for duration says:

    Must be something that parses into a Duration. If not specified, each event will appear to have the default duration.

    So instead of setting end you need to calculate the difference between the start and end times, and use that as the duration. The example data you've supplied makes this more complicated because the two dates are not even same day - the end date is before the start date!! So we have to extract just the times first, and use those. Luckily momentJS can help us with this.

    Your code is also setting some other properties that fullCalendar does not need (see https://fullcalendar.io/docs/v5/event-parsing for a list of what is recognised), and moment can parse your timestamps directly without needing a Date object first.

    Therefore your event-processing code can be re-written as follows:

      if (res?.length > 0) {
        _self.calendarEvents = res;
        _self.lstEvents = _self.calendarEvents.map((x) => {
          let utcStart = moment.unix(x.when.start_time).utc();
          let startTime = moment();
          startTime.set({ "hour": utcStart.hour(), "minute": utcStart.minute(), "second": utcStart.second() });
          console.log ("utcStart:" + utcStart.format("YYYY-MM-DD HH:mm:ss"), startTime.format("YYYY-MM-DD HH:mm:ss"));
    
          let utcEnd = moment.unix(x.when.end_time).utc();
          let endTime = moment();
          endTime.set({ "hour": utcEnd.hour(), "minute": utcEnd.minute(), "second": utcEnd.second() });
          console.log ("utcEndtime:" + utcEnd.format("YYYY-MM-DD HH:mm:ss"), endTime.format("YYYY-MM-DD HH:mm:ss"));
    
          if (x?.recurrence?.rrule[0] && x?.recurrence?.rrule[0] != undefined) {
            return {
              duration: moment.duration(endTime.diff(startTime)).asMilliseconds(),
              rrule:
                "DTSTART:" +
                utcStart.format("YYYYMMDDTHHmmss[Z]") +
                "\n" +
                x?.recurrence?.rrule[0]
            };
          } else {
            return {
              ...x,
              start: utcStart.format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              end: utcEnd.format("YYYY-MM-DDTHH:mm:ss.sssZ"),
              allDay: false
            };
          }
        });
        console.log(JSON.stringify(_self.lstEvents));
        successCallback(_self.lstEvents);
      } else {
        successCallback(_self.lstEvents);
      }
    

    Live demo: https://codepen.io/ADyson82/pen/PoxmWLp

    Secondly, regarding the problem you mentioned where it shows events on Mondays instead of Tuesdays, I could not reproduce that issue using your code. I don't think there is actually a problem to solve - maybe you should double-check what you were seeing. It could just be because you are passing the times to fullCalendar in UTC, and then your timezone translation means that the event moves over into the following day.