Skip to content

Calendar event filtering and timezone improvements#63

Closed
CR0CKER wants to merge 8 commits intosawhney17:mainfrom
CR0CKER:feature/filter-declined-events
Closed

Calendar event filtering and timezone improvements#63
CR0CKER wants to merge 8 commits intosawhney17:mainfrom
CR0CKER:feature/filter-declined-events

Conversation

@CR0CKER
Copy link
Copy Markdown

@CR0CKER CR0CKER commented Feb 5, 2026

Motivation

This PR addresses several long-standing issues with calendar event handling:

  1. User pain point: Users see declined invitations cluttering their daily notes, even though they're not attending
  2. Bug: Cancelled/deleted events still appear in the calendar import
  3. Bug: When a recurring meeting is rescheduled, it appears on BOTH the old and new dates
  4. Bug: Events from different timezones (e.g., US-based meetings) display incorrect times in other timezones (e.g., Europe)
  5. Bug: Events don't sort chronologically, making daily notes hard to read

Summary

This PR includes multiple related improvements for calendar event handling, timezone display, and event filtering:

  • Filter declined events: Add optional filtering to hide events where user has declined the invitation
  • Filter deleted events: Properly handle cancelled events (STATUS:CANCELLED) and excluded recurring instances (EXDATE)
  • Fix rescheduled events: Prevent recurring events from appearing on both original and rescheduled dates
  • Fix timezone display: Correct timezone handling for recurring events from different timezones
  • Fix event sorting: Sort events by UTC time to match displayed chronological order

Changes

1. Declined Event Filtering (89cc0d6)

New Settings:

  • userEmail (string, optional): Your email address to identify declined events
  • hideDeclinedEvents (boolean, default: true): Enable/disable filtering

Implementation:

  • Add shouldFilterDeclinedEvent() helper that checks attendee PARTSTAT property
  • Filter applied to: non-recurring events, recurring instances, and rescheduled instances
  • Feature is opt-in and backward compatible (disabled if no email configured)

Example usage:

Settings → userEmail: "user@example.com"
Settings → hideDeclinedEvents: true (default)

Result: Events where you've clicked "Decline" in your calendar app won't appear in Logseq.

2. Deleted Event Filtering (39aae4a)

Bug fix: node-ical returns exdate (excluded dates) as an object, not an array

Implementation:

  • Add isCancelledEvent() to filter events with STATUS:CANCELLED (iCalendar spec)
  • Fix EXDATE handling: Use Object.values() to extract dates regardless of structure
  • Properly exclude single deleted instances from recurring events

Example: If you delete "June 15th" from a recurring weekly meeting, that date no longer appears.

3. Rescheduled Event Handling (0ac10e3)

Bug fix: Recurring events appeared on both original and rescheduled dates

Implementation:

  • Check event.recurrences property for modified instances
  • Skip original occurrence when rescheduled version exists
  • Add rescheduled instances to events array with correct date/time

Example: If you reschedule Monday's 2pm meeting to Tuesday 3pm, it only appears on Tuesday at 3pm (not both days).

4. Timezone Display Fix (1086e0b)

Bug fix: Recurring events from different timezones displayed incorrect times

Root cause: Previous code parsed dtstart without specifying timezone, causing time extraction in wrong timezone.

Implementation:

  • Fix recurring event time parsing using moment.tz() with event's timezone (index.ts:336)
  • Display times in user's local timezone instead of event timezone (index.ts:568-569)
  • Fix sorting to match displayed times (index.ts:169-177)

Example: An "8:30 AM America/New_York" meeting now correctly displays as "2:30 PM" in Europe/Amsterdam, not "8:30 AM".

5. Event Sorting Fix (2e5962b)

Bug fix: Events didn't sort chronologically

Implementation:

  • Sort by UTC timestamps instead of timezone-aware times
  • Filter out events with invalid dates before sorting
  • Events now appear in correct chronological order as displayed

Backward Compatibility

No breaking changes:

  • Declined event filtering is disabled by default (requires userEmail to be configured)
  • All existing calendars continue to work without modification
  • New settings have sensible defaults

⚠️ Note: If users configure userEmail, hideDeclinedEvents defaults to true. Users who want to see declined events should set this to false.

Testing

Manual Test Plan

  • Declined events: Configure userEmail in settings, decline a calendar event in your calendar app, run import → verify event doesn't appear
  • Cancelled events: Cancel an event in your calendar app, run import → verify it doesn't appear
  • Deleted recurring instances: Delete one instance of a recurring event, run import → verify that date is skipped
  • Rescheduled recurring events: Reschedule one instance of a recurring meeting to a different date/time, run import → verify it appears only on the new date/time
  • Timezone display: Import a calendar with events in a different timezone (e.g., US events viewed from Europe), verify times display in your local timezone
  • Event sorting: Import multiple events throughout the day, verify they appear in chronological order

Test Setup

For testing timezone issues, you can use this public test calendar with US/Eastern events:

webcal://example-ical-url-with-timezone-events

Documentation Impact

Settings documentation needed:
The plugin settings UI now includes two new fields that should be documented:

  • userEmail: User's email address (optional, used for declined event filtering)
  • hideDeclinedEvents: Toggle for declined event filtering (default: true)

Related Issues

This PR supersedes PR #62 (event sorting fix) by including that fix plus additional improvements.

Potentially related to issue #53 (expanding RRule to include 2024) - this PR generates recurring events from 1 year ago to 2 years in the future.

🤖 Generated with Claude Code

CR0CKER and others added 8 commits December 9, 2025 11:15
- Fixed hardcoded date range (2021-2023) in recurring event generation
  Now dynamically generates events from 1 year ago to 2 years in future
- Fixed timezone handling for recurring events with tzid
- Added null check in parseLocation() to prevent "TypeError: b is not iterable"
  when event locations don't contain URLs
- Added cache-busting headers to force fresh calendar data

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This is the confirmed working version of the plugin.

Bug fixes included:
- Fixed hardcoded date range (2021-2023) for recurring events
  Now dynamically generates from 1 year ago to 2 years in future
- Fixed timezone handling for recurring events with tzid
- Fixed parseLocation() null check preventing "TypeError: b is not iterable"
- Removed CORS-triggering headers (Cache-Control, Pragma, Expires)
- Added cache-busting URL parameter for fresh calendar data

Build configuration:
- Added .parcelrc configuration
- Built with Node 16.20.2 using NVM
- Updated package-lock.json with esbuild dev dependency

Deployment:
- Plugin works in Developer mode (file:// protocol)
- Load as unpacked plugin from source directory
- Tested and confirmed working on December 9, 2025

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…sion

Recurring events with timezone information (tzid) were being displayed with incorrect times because the timezone was lost during JavaScript Date conversion. This caused events to be shown in the local system timezone instead of the event's original timezone.

Changes:
- Preserve timezone info in recurring event objects
- Update formatTime() to accept optional timezone parameter and use moment-timezone for accurate time extraction
- Calculate end times correctly for recurring events based on original duration
- Pass timezone info through the formatting pipeline

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Filter out events with invalid dates to prevent NaN comparisons
- Sort events by displayed time in their original timezone, not absolute timestamps
- Fix timezone conversion for recurring events using moment.tz object notation
- Correct insertion order to match chronological sort order

This ensures events appear in the correct chronological order (e.g., 13:45, 14:30, 16:00)
even when events are created in different timezones.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When a single occurrence of a recurring event is rescheduled in Google
Calendar or other iCal systems, the calendar stores:
1. The recurring event with an RRULE (generates all occurrences)
2. Modified instances in a "recurrences" property keyed by date
3. Optionally an EXDATE list of excluded dates

The plugin was generating all RRULE occurrences without checking if they
had been rescheduled, causing events to appear on both old and new dates.

This fix:
- Checks the recurrences property for modified instances
- Skips generating RRULE occurrences that have been rescheduled
- Adds the rescheduled instances from recurrences with their new date/time
- Also checks EXDATE for additional excluded dates (cancelled occurrences)
- Logs skipped and rescheduled events to console for debugging

Tested with "Weekly Audience Meeting" which was moved from Jan 13 to Jan 14:
- Jan 13: Event no longer appears (correctly skipped)
- Jan 14: Event appears at rescheduled time (correctly added)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This feature allows users to hide events they've declined from their calendar imports.

Changes:
- Add userEmail setting for user's email address (optional)
- Add hideDeclinedEvents setting to enable/disable filtering (default: true)
- Create shouldFilterDeclinedEvent() helper function that checks attendee PARTSTAT
- Apply filtering to non-recurring events, recurring instances, and rescheduled instances
- Feature is opt-in and backward compatible (disabled if no email configured)

When enabled, events where the user's attendance status is "DECLINED" will be
automatically filtered out during calendar parsing, preventing them from appearing
in Logseq daily notes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add filtering for events with STATUS:CANCELLED (iCalendar spec)
- Fix EXDATE handling for deleted recurring event instances
- Bug: node-ical returns exdate as object with date keys, not array
- Solution: Always use Object.values() to extract dates from exdate
- Now properly excludes single deleted instances from recurring events

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Previous timezone fix (commit 50cab8d) introduced a bug where recurring
events from different timezones displayed at incorrect times. For example,
an 8:30 AM America/New_York event showed as 8:30 AM in Europe/Amsterdam
instead of the correct 2:30 PM local time.

Root cause: When extracting time components from recurring events, the code
was parsing the event's dtstart without specifying the timezone:
  moment(event.rrule.origOptions.dtstart)
This interpreted the timestamp in the local timezone instead of the event's
timezone, causing hours/minutes to be extracted incorrectly.

Changes:
1. Fix timezone parsing for recurring events (rawParser, line 336)
   - Now uses moment.tz() with the event's tzid to parse dtstart correctly
   - Ensures time components are extracted in the event's timezone

2. Display times in user's local timezone (insertJournalBlocks, lines 568-569)
   - Removed timezone parameter from formatTime() calls
   - Times now display in user's local timezone, matching standard calendar behavior

3. Fix event sorting to match displayed times (sortDate, lines 169-177)
   - Sort by UTC timestamps instead of event-specific timezones
   - Ensures events appear in correct chronological order as displayed

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@CR0CKER
Copy link
Copy Markdown
Author

CR0CKER commented Apr 24, 2026

Superseded — see https://github.com/CR0CKER/logseq-calendars-plugin (logseq-ical-sync).

@CR0CKER CR0CKER closed this Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant