@@ -120,14 +120,53 @@ export function parseRRule(recurrence?: string[]): string | undefined {
120120 return rrule ? rrule . substring ( 6 ) : undefined ; // Remove 'RRULE:' prefix
121121}
122122
123+ /**
124+ * Parses an iCalendar date string into a JavaScript Date.
125+ * Handles formats: YYYYMMDD, YYYYMMDDTHHMMSS, YYYYMMDDTHHMMSSZ
126+ */
127+ function parseICalDate ( dateStr : string ) : Date | null {
128+ // Remove any whitespace
129+ const d = dateStr . trim ( ) ;
130+
131+ // All-day date: YYYYMMDD (8 chars)
132+ if ( / ^ \d { 8 } $ / . test ( d ) ) {
133+ const year = d . slice ( 0 , 4 ) ;
134+ const month = d . slice ( 4 , 6 ) ;
135+ const day = d . slice ( 6 , 8 ) ;
136+ return new Date ( `${ year } -${ month } -${ day } ` ) ;
137+ }
138+
139+ // DateTime with or without Z: YYYYMMDDTHHMMSS or YYYYMMDDTHHMMSSZ
140+ if ( / ^ \d { 8 } T \d { 6 } Z ? $ / . test ( d ) ) {
141+ const year = d . slice ( 0 , 4 ) ;
142+ const month = d . slice ( 4 , 6 ) ;
143+ const day = d . slice ( 6 , 8 ) ;
144+ const hour = d . slice ( 9 , 11 ) ;
145+ const minute = d . slice ( 11 , 13 ) ;
146+ const second = d . slice ( 13 , 15 ) ;
147+ const isUtc = d . endsWith ( "Z" ) ;
148+ return new Date (
149+ `${ year } -${ month } -${ day } T${ hour } :${ minute } :${ second } ${ isUtc ? "Z" : "" } `
150+ ) ;
151+ }
152+
153+ // Fallback: try native parsing
154+ const parsed = new Date ( d ) ;
155+ return isNaN ( parsed . getTime ( ) ) ? null : parsed ;
156+ }
157+
123158export function parseExDates ( recurrence ?: string [ ] ) : Date [ ] {
124159 if ( ! recurrence ?. length ) return [ ] ;
125160
126161 return recurrence
127162 . filter ( ( rule ) => rule . startsWith ( "EXDATE" ) )
128163 . flatMap ( ( rule ) => {
129164 const dates = rule . split ( ":" ) [ 1 ] ;
130- return dates ? dates . split ( "," ) . map ( ( d ) => new Date ( d ) ) : [ ] ;
165+ if ( ! dates ) return [ ] ;
166+ return dates
167+ . split ( "," )
168+ . map ( ( d ) => parseICalDate ( d ) )
169+ . filter ( ( d ) : d is Date => d !== null ) ;
131170 } ) ;
132171}
133172
@@ -138,7 +177,11 @@ export function parseRDates(recurrence?: string[]): Date[] {
138177 . filter ( ( rule ) => rule . startsWith ( "RDATE" ) )
139178 . flatMap ( ( rule ) => {
140179 const dates = rule . split ( ":" ) [ 1 ] ;
141- return dates ? dates . split ( "," ) . map ( ( d ) => new Date ( d ) ) : [ ] ;
180+ if ( ! dates ) return [ ] ;
181+ return dates
182+ . split ( "," )
183+ . map ( ( d ) => parseICalDate ( d ) )
184+ . filter ( ( d ) : d is Date => d !== null ) ;
142185 } ) ;
143186}
144187
0 commit comments