Skip to content

fix(dashboard): honor fixed-offset event timezones - #8649

Closed
pi0n00r wants to merge 1 commit into
nextcloud:mainfrom
pi0n00r:fix/dashboard-fixed-offset-tz
Closed

pi0n00r wants to merge 1 commit into
nextcloud:mainfrom
pi0n00r:fix/dashboard-fixed-offset-tz

Conversation

@pi0n00r

@pi0n00r pi0n00r commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • normalize valid UTC+/-HH:MM and UTC+/-HHMM TZID values before the dashboard widget compares or formats event start times
  • preserve the event wall clock while attaching its explicit fixed offset
  • leave UTC, IANA TZIDs, floating values, all-day values, and source event data unchanged

Problem

Sabre VObject falls back to PHP's default timezone when a non-IANA fixed-offset TZID such as UTC-04:00 cannot be resolved. The Calendar view can still render the wall time correctly, but CalendarWidget receives a DateTimeImmutable carrying the fallback timezone and emits the wrong sinceId and relative subtitle.

For example, DTSTART;TZID="UTC-04:00":20260728T111500 can be emitted by the dashboard as 11:15 UTC instead of 11:15 at -04:00.

Validation

  • added a full widget regression covering fixed-offset normalization
  • asserted the original search result and TZID remain unchanged
  • PHP 8.4 syntax checks pass for the implementation and test

The change is display-only and performs no calendar write.

@pi0n00r
pi0n00r force-pushed the fix/dashboard-fixed-offset-tz branch from 4ac7d19 to 4b3751b Compare July 28, 2026 05:46
@pi0n00r pi0n00r closed this Jul 28, 2026
@pi0n00r
pi0n00r deleted the fix/dashboard-fixed-offset-tz branch July 28, 2026 05:55
@pi0n00r
pi0n00r restored the fix/dashboard-fixed-offset-tz branch July 28, 2026 06:04
@pi0n00r pi0n00r reopened this Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@SebastianKrupinski

Copy link
Copy Markdown
Contributor

Hi @pi0n00r

Sorry its taken awhile to comment on this.

What issue are you trying to solve with this?

@pi0n00r

pi0n00r commented Sep 5, 2026

Copy link
Copy Markdown
Author

Hi @SebastianKrupinski, thanks for taking a look.

This fixes a reproducible Dashboard Upcoming events display bug for timed CalDAV objects that use a fixed-offset TZID rather than an IANA name, for example:

DTSTART;TZID=UTC-04:00:20260728T111500

Sabre retains the TZID parameter, but when it cannot resolve that value as a timezone it constructs the DateTimeImmutable using PHP's default timezone. The Calendar/Tasks views can still show the intended 11:15 wall-clock value, while CalendarWidget consumes the fallback timestamp and emits the wrong sinceId and relative-time subtitle. In the example above, the Dashboard effectively treats 11:15 at -04:00 as 11:15 UTC, a four-hour shift.

The change corrects only the widget's projection: it preserves the wall clock and applies the explicit offset before timestamp comparison/formatting. It does not mutate the source event, and leaves UTC, IANA TZIDs, floating values, and all-day VALUE=DATE values unchanged. The regression test covers both the corrected timestamp and source immutability. We have also validated the patch against the user-visible failure on Calendar 6.5.3 and 6.5.4.

If fixed-offset TZIDs should instead be normalized at an earlier shared layer, I am happy to move the correction there; I kept this PR scoped to the demonstrated Dashboard inconsistency.

@SebastianKrupinski

Copy link
Copy Markdown
Contributor

Can I ask which client creates events with "UTC-04:00"?

@pi0n00r

pi0n00r commented Sep 7, 2026

Copy link
Copy Markdown
Author

In our reproduction, the producer was the CalDAV client in cbcoutinho/nextcloud-mcp-server (through our fork of it).

Its then-current event create/update path parsed an ISO 8601 value such as 2026-07-28T11:15:00-04:00 into a fixed-offset Python datetime and passed that to Python's icalendar library. That serialized the property as, for example:

DTSTART;TZID="UTC-04:00":20260728T111500

We subsequently corrected that producer path to emit TZID=America/Toronto when the supplied offset matches Toronto on the event date: pi0n00r/nextcloud-mcp-server@ab67cdc

The Calendar patch was prompted by records created before that correction and keeps the Dashboard projection robust when it encounters such a fixed-offset TZID.

@pi0n00r

pi0n00r commented Sep 9, 2026

Copy link
Copy Markdown
Author

Added a follow-up regression fix in 94121dc. Relative-day formatting now compares the event and request clock in the same display timezone, so a late-evening local request does not label an event two local calendar dates away as tomorrow. Timed values are converted as instants; all-day values retain their calendar date. The formatter receives the frozen request time explicitly.\n\nRegression coverage uses a generic 2026-09-08 23:30 America/Toronto request and a 2026-09-10 UTC event, and separately verifies all-day date preservation. Locally verified: focused CalendarWidget suite 13 tests / 50 assertions; full Calendar PHP unit suite 287 tests / 1,164 assertions; PHP syntax, style, and diff checks passed.

@SebastianKrupinski
SebastianKrupinski force-pushed the fix/dashboard-fixed-offset-tz branch from 94121dc to 51c113f Compare September 14, 2026 16:56
Signed-off-by: pi0n00r <131018595+pi0n00r@users.noreply.github.com>
@SebastianKrupinski
SebastianKrupinski force-pushed the fix/dashboard-fixed-offset-tz branch from 51c113f to 624f4e0 Compare September 14, 2026 16:57
@SebastianKrupinski

Copy link
Copy Markdown
Contributor

Closing this in favour of fixing this properly in sabre sabre-io/vobject#790

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants