Skip to content

Commit

Permalink
Merge pull request #113 from cloud-atlas-ai:coerce-to-utc-when-using-…
Browse files Browse the repository at this point in the history
…rrule

Fix to address timezone offsetting issues
  • Loading branch information
muness authored Feb 25, 2024
2 parents c1c4498 + 6cc4feb commit ba0d11d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 92 deletions.
2 changes: 1 addition & 1 deletion manifest-beta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "ics",
"name": "ICS",
"version": "1.6.1test",
"version": "1.6.2-beta3",
"minAppVersion": "1.5.3",
"description": "Parse multiple ICS files to include in your notes. Designed for Daily Notes and the Day Planner format. Through templates you can customize it for other use cases.",
"author": "Cloud Atlas",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-ics",
"version": "1.6.1",
"version": "1.6.2-beta3",
"description": "Adds events from calendar ics published on the web to daily note on demand. Daily Note or Periodic Notes plugins: specifically it gets the date to search for events during from the currently open daily note.",
"main": "dist/main.js",
"scripts": {
Expand Down
184 changes: 97 additions & 87 deletions src/icalUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,107 +4,117 @@ import { moment } from "obsidian";

export function extractMeetingInfo(e: any): { callUrl: string, callType: string } {

// Check for Google Meet conference data
if (e["GOOGLE-CONFERENCE"]) {
return { callUrl: e["GOOGLE-CONFERENCE"], callType: 'Google Meet' };
}
// Check if the location contains a Zoom link
if (e.location && e.location.includes('zoom.us')) {
return { callUrl: e.location, callType: 'Zoom' };
}
if (e.description) {
const skypeMatch = e.description.match(/https:\/\/join.skype.com\/[a-zA-Z0-9]+/);
if (skypeMatch) {
return { callUrl: skypeMatch[0], callType: 'Skype' };
}

const teamsMatch = e.description.match(/(https:\/\/teams\.microsoft\.com\/l\/meetup-join\/[^>]+)/);
if (teamsMatch) {
return { callUrl: teamsMatch[0], callType: 'Microsoft Teams' };
}
}
return { callUrl: null, callType: null };
// Check for Google Meet conference data
if (e["GOOGLE-CONFERENCE"]) {
return { callUrl: e["GOOGLE-CONFERENCE"], callType: 'Google Meet' };
}
// Check if the location contains a Zoom link
if (e.location && e.location.includes('zoom.us')) {
return { callUrl: e.location, callType: 'Zoom' };
}
if (e.description) {
const skypeMatch = e.description.match(/https:\/\/join.skype.com\/[a-zA-Z0-9]+/);
if (skypeMatch) {
return { callUrl: skypeMatch[0], callType: 'Skype' };
}

const teamsMatch = e.description.match(/(https:\/\/teams\.microsoft\.com\/l\/meetup-join\/[^>]+)/);
if (teamsMatch) {
return { callUrl: teamsMatch[0], callType: 'Microsoft Teams' };
}
}
return { callUrl: null, callType: null };
}

function adjustDateToOriginalTimezone(originalDate: Date, currentDate: Date, tzid: string): Date {
const momentOriginal = tz(originalDate, tzid);
const momentCurrent = tz(currentDate, tzid);
const momentOriginal = tz(originalDate, tzid);
const momentCurrent = tz(currentDate, tzid);

// Calculate the difference in hours and minutes between the original and current
const hourOffset = momentOriginal.hour() - momentCurrent.hour();
const minuteOffset = momentOriginal.minute() - momentCurrent.minute();
// Calculate the difference in hours and minutes between the original and current
const hourOffset = momentOriginal.hour() - momentCurrent.hour();
const minuteOffset = momentOriginal.minute() - momentCurrent.minute();

// Adjust the current date by the offset to keep the local time constant
return momentCurrent.add(hourOffset, 'hours').add(minuteOffset, 'minutes').toDate();
// Adjust the current date by the offset to keep the local time constant
return momentCurrent.add(hourOffset, 'hours').add(minuteOffset, 'minutes').toDate();
}

export function filterMatchingEvents(icsArray: any[], dayToMatch: string) {
const localTimeZone = tz.zone(tz.guess());

return icsArray.reduce((matchingEvents, event) => {
var hasRecurrenceOverride = false
if (event.recurrences !== undefined) {
for (let date in event.recurrences) {
if (moment(date).isSame(dayToMatch, "day")) {
hasRecurrenceOverride = true;
}

return icsArray.reduce((matchingEvents, event) => {
var hasRecurrenceOverride = false
if (event.recurrences !== undefined) {
for (let date in event.recurrences) {
if (moment(date).isSame(dayToMatch, "day")) {
hasRecurrenceOverride = true;
}
const recurrence = event.recurrences[date];
if (moment(recurrence.start).isSame(dayToMatch, "day")) {
matchingEvents.push(recurrence);
hasRecurrenceOverride = true;
}
}
}
if (typeof event.rrule !== 'undefined' && !hasRecurrenceOverride) {
event.rrule.between(moment(dayToMatch).startOf('day').toDate(), moment(dayToMatch).endOf('day').toDate()).forEach(date => {
// We need to clone the event and override the date

const clonedEvent = { ...event };

console.debug('Found a recurring event to clone: ', event.summary, ' on ', date, 'at ', event.start.toString());
console.debug("RRULE origOptions:", event.rrule.origOptions);

// But timezones...
if (event.rrule != undefined && event.rrule.origOptions.tzid) {
const tzid = event.rrule.origOptions.tzid;
console.debug("Event rrule.origOptions.tzid:", tzid);
// Adjust the cloned event start and end times to the original event timezone
clonedEvent.start = adjustDateToOriginalTimezone(event.start, date, tzid);
clonedEvent.end = adjustDateToOriginalTimezone(event.end, date, tzid);
} else {
// If there is no timezone information, assume the event time should not change
clonedEvent.start = new Date(date);
clonedEvent.end = new Date(date.getTime() + (event.end.getTime() - event.start.getTime()));
}

// Remove rrule property from clonedEvent
delete clonedEvent.rrule;

console.debug("Cloned event:", {
...clonedEvent,
start: clonedEvent.start.toString(),
end: clonedEvent.end.toString()
});

matchingEvents.push(clonedEvent);
});
} else if (!hasRecurrenceOverride) {
if (moment(event.start).isSame(dayToMatch, "day")) {
matchingEvents.push(event);
}
}
return matchingEvents;
}, []);;
}
}
if (typeof event.rrule !== 'undefined' && !hasRecurrenceOverride) {
// Fetch events from yesterday to tomorrow
const localStartOfYesterday = moment(dayToMatch).subtract(1, 'day').startOf('day').toDate();
const localEndOfTomorrow = moment(dayToMatch).add(1, 'day').endOf('day').toDate();

event.rrule.between(localStartOfYesterday, localEndOfTomorrow).forEach(date => {

// now the date is in the local timezone, so we need to apply the offset to get it back to UTC
const offset = moment(date).utcOffset();
date = moment(date).subtract(offset, 'minutes').toDate();

// We need to clone the event and override the date
const clonedEvent = { ...event };

console.debug('Found a recurring event to clone: ', event.summary, ' on ', date, 'at ', event.start.toString());

// But timezones...
if (event.rrule != undefined && event.rrule.origOptions.tzid) {
const tzid = event.rrule.origOptions.tzid;
console.debug("Event rrule.origOptions.tzid:", tzid);
// Adjust the cloned event start and end times to the original event timezone
clonedEvent.start = adjustDateToOriginalTimezone(event.start, date, tzid);
clonedEvent.end = adjustDateToOriginalTimezone(event.end, date, tzid);
} else {
// If there is no timezone information, assume the event time should not change
clonedEvent.start = new Date(date);
clonedEvent.end = new Date(date.getTime() + (event.end.getTime() - event.start.getTime()));
}

// Remove rrule property from clonedEvent
delete clonedEvent.rrule;

// Check if the event is really during 'today' in the local timezone
const eventStartLocal = moment(clonedEvent.start);
if (eventStartLocal.isSame(dayToMatch, 'day')) {
console.debug("Cloned event:", {
...clonedEvent,
start: clonedEvent.start.toString(),
end: clonedEvent.end.toString()
});

matchingEvents.push(clonedEvent);
}
});
} else if (!hasRecurrenceOverride) {
if (moment(event.start).isSame(dayToMatch, "day")) {
matchingEvents.push(event);
}
}
return matchingEvents;
}, []);;
}

export function parseIcs(ics: string) {
var data = ical.parseICS(ics);
var vevents = [];

for (let i in data) {
if (data[i].type != "VEVENT")
continue;
vevents.push(data[i]);
}
return vevents;
var data = ical.parseICS(ics);
var vevents = [];

for (let i in data) {
if (data[i].type != "VEVENT")
continue;
vevents.push(data[i]);
}
return vevents;
}
5 changes: 4 additions & 1 deletion versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@
"1.5.4": "1.5.3",
"1.6.0": "1.5.3",
"1.6.1test": "1.5.3",
"1.6.1": "1.5.3"
"1.6.1": "1.5.3",
"1.6.2-rrule-utc-coercion": "1.5.3",
"1.6.2-beta2": "1.5.3",
"1.6.2-beta3": "1.5.3"
}

0 comments on commit ba0d11d

Please sign in to comment.