UNPKG

icalendar-events

Version:

A RFC5545 compliant parser for iCalendar VEVENT with time zone support and accurate recurring events generation.

68 lines (50 loc) 2.61 kB
import { DateTime } from 'luxon' export function parseICalDateTime(line: string): DateTime[] { let dateTimeList: DateTime[] = [] const lineUC: string = line.trim().toUpperCase() if(lineUC.includes("UNTIL=")) { //case UNTIL=20130130 or UNTIL=20130130T230000 or UNTIL=20130130T230000Z const parts: string[] = lineUC.split("UNTIL=") if(parts.length < 2) throw new Error(`parseICalDateTime: Invalid DateTime ${line}`) // UNTIL can have only 1 value dateTimeList.push(parseDateString(parts[1])) } else if(line.includes(":")) { // Case DTSTART;TZID=Asia/Tokyo:20201027T163000 or DTSTART:20201027T163000 or DTSTART:20201027T163000Z // or RDATE;VALUE=DATE:19970304,19970504,19970704,19970904 // or EXDATE:20201027T163000Z,20201127T163000Z,20201227T163000Z // or RDATE;TZID=Asia/Tokyo:20201027T163000,20201127T163000,20201227T163000 for example // (case RDATE;VALUE=PERIOD is handled in parseICalPeriod function) const parts: string[] = line.split(":") if(parts.length < 2) throw new Error(`parseICalDateTime: Invalid DateTime ${line}`) let tzid: string | undefined = process.env.ICALEVENTS_LOCAL_TZ if (parts[0].replace(/tzid/,"TZID").includes("TZID=")) { tzid = parts[0].split("TZID=")[1].split(";")[0].split(":")[0].trim() } // Multiple values separated by "," parts[1].split(",").forEach( (dateString: string): void => { dateTimeList.push(parseDateString(dateString, tzid)) }) } else { throw new Error(`parseICalDateTime: datetime could not be parsed ${line}`) } if(dateTimeList.length === 0 || !dateTimeList.every((dateTime: DateTime) => dateTime !== null && dateTime.isValid)) { throw new Error(`parseICalDateTime: Invalid DateTime ${line}`) } return dateTimeList } export function parseDateString(dateString: string, tzid?: string): DateTime { let dateStringTrimmed: string = dateString.trim().toUpperCase() if(dateStringTrimmed.match(/^\d{8}T\d{6}Z$/) !== null) { return DateTime.fromFormat(dateStringTrimmed, "yyyyMMdd'T'HHmmss'Z'", {zone: 'UTC'}) } else if(dateStringTrimmed.match(/^\d{8}T\d{6}$/) !== null) { tzid = tzid ?? 'local' return DateTime.fromFormat(dateStringTrimmed, "yyyyMMdd'T'HHmmss", {zone: tzid}) } else if(dateStringTrimmed.match(/^\d{8}$/) !== null) { //Date so Time zone is set to UTC const date: DateTime = DateTime.fromFormat(dateStringTrimmed, "yyyyMMdd", {zone: 'UTC'}) date.isDate = true return date } else { throw new Error(`parseICalDateTime: datetime could not be parsed: ${dateString}`) } }