@@ -27,15 +27,14 @@ export function extractMeetingInfo(e: any): { callUrl: string, callType: string
2727}
2828
2929function applyRecurrenceDateAndTimezone ( originalDate : Date , currentDate : Date , tzid : string ) : Date {
30- const momentOriginal = tz ( originalDate , tzid ) ;
31- const momentCurrent = tz ( currentDate , tzid ) ;
30+ const originalMoment = tz ( originalDate , tzid ) ;
3231
33- // Calculate the difference in hours and minutes between the original and current
34- const hourOffset = momentOriginal . hour ( ) - momentCurrent . hour ( ) ;
35- const minuteOffset = momentOriginal . minute ( ) - momentCurrent . minute ( ) ;
32+ // Create a moment in the target timezone using just the date components of currentDate
33+ // This avoids timezone conversion issues with the recurrence date
34+ const currentDateMoment = moment . utc ( currentDate ) ;
35+ const adjustedMoment = tz ( `${ currentDateMoment . format ( 'YYYY-MM-DD' ) } ${ originalMoment . format ( 'HH:mm:ss' ) } ` , tzid ) ;
3636
37- // Adjust the current date by the offset to keep the local time constant
38- return momentCurrent . add ( hourOffset , 'hours' ) . add ( minuteOffset , 'minutes' ) . toDate ( ) ;
37+ return adjustedMoment . toDate ( ) ;
3938}
4039
4140function isExcluded ( recurrenceDate : moment . Moment , exdateArray : moment . Moment [ ] ) : boolean {
@@ -65,29 +64,35 @@ function processRecurrenceOverrides(event: any, sortedDaysToMatch: string[], exc
6564}
6665
6766function processRecurringRules ( event : any , sortedDaysToMatch : string [ ] , excludedDates : moment . Moment [ ] , matchingEvents : any [ ] ) {
68- const localStartOfRange = moment ( sortedDaysToMatch . first ( ) ) . subtract ( 1 , 'day' ) . startOf ( 'day' ) . toDate ( ) ;
69- const localEndOfRange = moment ( sortedDaysToMatch . last ( ) ) . add ( 1 , 'day' ) . endOf ( 'day' ) . toDate ( ) ;
67+ const tzid = event . rrule . origOptions . tzid || 'UTC' ;
68+
69+ // Use UTC for rrule calculations to avoid timezone offset issues
70+ const startOfRange = moment . utc ( sortedDaysToMatch . first ( ) ) . subtract ( 1 , 'day' ) . startOf ( 'day' ) . toDate ( ) ;
71+ const endOfRange = moment . utc ( sortedDaysToMatch . last ( ) ) . add ( 1 , 'day' ) . endOf ( 'day' ) . toDate ( ) ;
7072
7173 // Get recurrence dates within the range
72- const recurrenceDates = event . rrule . between ( localStartOfRange , localEndOfRange , true ) ;
74+ const recurrenceDates = event . rrule . between ( startOfRange , endOfRange , true ) ;
7375
7476 recurrenceDates . forEach ( recurrenceDate => {
75- const recurrenceMoment = tz ( recurrenceDate , event . rrule . origOptions . tzid || 'UTC' ) ;
76-
77- // Clone the event and use the recurrence date directly if start and end times are present
78- const clonedEvent = { ...event } ;
79- clonedEvent . start = applyRecurrenceDateAndTimezone ( event . start , recurrenceDate , event . rrule . origOptions . tzid ) ;
80- clonedEvent . end = applyRecurrenceDateAndTimezone ( event . end , recurrenceDate , event . rrule . origOptions . tzid ) ;
77+ const recurrenceMoment = tz ( recurrenceDate , tzid ) . startOf ( 'day' ) ;
8178
8279 if ( isExcluded ( recurrenceMoment , excludedDates ) ) {
8380 console . debug ( `Skipping excluded recurrence: ${ event . summary } on ${ recurrenceMoment . format ( 'YYYY-MM-DD' ) } ` ) ;
8481 return ;
8582 }
8683
84+ // Clone the event and apply proper timezone-aware date/time calculation
85+ const clonedEvent = { ...event } ;
86+ clonedEvent . start = applyRecurrenceDateAndTimezone ( event . start , recurrenceDate , tzid ) ;
87+ clonedEvent . end = applyRecurrenceDateAndTimezone ( event . end , recurrenceDate , tzid ) ;
88+
8789 delete clonedEvent . rrule ;
8890 clonedEvent . recurrent = true ;
8991
90- if ( moment ( clonedEvent . start ) . isBetween ( sortedDaysToMatch . first ( ) , sortedDaysToMatch . last ( ) , 'day' , '[]' ) ) {
92+ // Check if the recurrence falls within the requested date range using timezone-aware comparison
93+ const eventStartMoment = tz ( clonedEvent . start , tzid ) ;
94+ const eventStartDate = eventStartMoment . format ( 'YYYY-MM-DD' ) ;
95+ if ( sortedDaysToMatch . includes ( eventStartDate ) ) {
9196 console . debug ( `Adding recurring event: ${ clonedEvent . summary } ${ clonedEvent . start } - ${ clonedEvent . end } ` ) ;
9297 console . debug ( "Excluded dates:" , excludedDates . map ( date => date . format ( 'YYYY-MM-DD' ) ) ) ;
9398
0 commit comments