fix(calendar): make showEnd behavior more consistent across time formats#4059
Conversation
…eFormats showEnd: true now works for full-day events spanning multiple days in 'relative' and 'dateheaders' mode, not just 'absolute'. Also, when nextDaysRelative replaces the start with 'Tomorrow' etc., the end date is appended (e.g. 'Tomorrow - 17th Mar'). showEndsOnlyWithDuration suppresses the end date as expected. Closes MagicMirrorOrg#4053
|
Hi @KristjanESPERANTO , thank you for your interest and work. I verified your patch and confirmed it works perfectly with fullday event. However, this doesn't show the end for the 'Multiday events with time(full day not checked)', e.g. from 10:00AM 30.03.2026 to 11:00AM 02.04.2026 . |
Add electron test coverage for timed (non-full-day) multi-day events with showEnd enabled in `relative` and `dateheaders` modes. Use a yearly recurring mock ICS so tests stay stable over time and avoid "no upcoming events" failures as dates move on.
defaultmodules/calendar/calendar.js
Outdated
| Log.info("[calendar] not full day but within getRelative size"); | ||
| // If event is within getRelative hours, display 'in xxx' time format or moment.fromNow() | ||
| timeWrapper.innerHTML = `${CalendarUtils.capFirst(eventStartDateMoment.fromNow())}`; | ||
| } else if (this.config.showEnd && (!this.config.showEndsOnlyWithDuration || event.startDate !== event.endDate)) { |
There was a problem hiding this comment.
Thank you @KristjanESPERANTO for the quick response! And additional functionality for dateEndFormat as well.
This works perfectly with the corner case which is the multiple day with specific time values.
Luckily or not, I found this line affects the existing behavior. The single day event is showing the end date even though the start date and the end date are same.
I am not sure if this is expected behavior but this line seems like it is supposed to show the end date when the startDate and endDate are different. From my debugging, the event.startDate !== event.endDate returns always true even if the dates are same. (Please see the reds above)
For draft, I checked below code fits this case. I'd appreciate it if you check this once again.
} else if (this.config.showEnd && (!this.config.showEndsOnlyWithDuration && !eventStartDateMoment.isSame(eventEndDateMoment, "d"))) {
There was a problem hiding this comment.
I see your point. I need to think this through more deeply.
There was a problem hiding this comment.
@kkangshawn Can you have another look 🙂
There was a problem hiding this comment.
This works PERFECTLY. Thank you so much.
P.S. The new dateEndFormat distinguishing timed multiday from timed sameday is absolutely cool!
There was a problem hiding this comment.
Nice. Thanks for testing! 😃
Now let's wait for a review of another core maintainer.
… tokens Expand `dateFormatIncludesTime()` to resolve localized Moment tokens (`L`, `LL`, `LLL`, `LLLL` and lowercase variants) before checking for time parts. This prevents duplicated start times in same-day timed `showEnd` output (e.g. with `dateFormat: "LLL"`). Add an electron regression test and config fixture covering the `LLL` case.
Prevent appending timed event end/start times in relative mode when hideTime=true. Make LLL same-day test format-agnostic and add hideTime+showEnd regression coverage.
Replace repetitive showEnd permutations with shared helpers and case tables. Keep special assertions for LLL and hideTime while reducing duplication.
Move dateheaders, absolute, and relative time text generation into dedicated helper methods. Reduce branching in getDom while preserving behavior and existing output semantics.
Move showEnd fixture variants into one config file selected by MM_CALENDAR_SHOWEND_SCENARIO. Update calendar_spec to choose scenarios by name and remove per-scenario wrapper config files.
|
@khassel Thanks for merging! @kkangshawn Now that the merge is complete, I’d like to encourage you to use the develop branch on your mirror (at least until the next release) to see if these (and other) changes have caused any regressions 🙂 |
## Release Notes Thanks to: @angeldeejay, @in-voker, @JHWelch, @khassel, @KristjanESPERANTO, @rejas, @sdetweil >⚠️ This release needs nodejs version >=22.21.1 <23 || >=24 (no change to previous release) [Compare to previous Release v2.34.0](v2.34.0...v2.25.0) >⚠️ We introduced some internal changes with this release, please read [this forum post](https://forum.magicmirror.builders/topic/20138/upcoming-release-april-1-2026-breaking-changes-some-operational-changes) before upgrading! ### [core] - Prepare Release 2.35.0 (#4071) - docs: add security policy and vulnerability reporting guidelines (#4069) - refactor: simplify internal `require()` calls (#4056) - allow environment variables in cors urls (#4033) - fix cors proxy getting binary data (e.g. png, webp) (#4030) - fix: correct secret redaction and optimize loadConfig (#4031) - change loading config.js, allow variables in config.js and try to protect sensitive data (#4029) - remove kioskmode (#4027) - Add dark theme logo (#4026) - move custom.css from css to config (#4020) - move default modules from /modules/default to /defaultmodules (#4019) - update node versions in workflows (#4018) - [core] refactor: extract and centralize HTTP fetcher (#4016) - fix systeminformation not displaying electron version (#4012) - Update node-ical and support it's rrule-temporal changes (#4010) - Change default start scripts from X11 to Wayland (#4011) - refactor: unify favicon for index.html and Electron (#4006) - [core] run systeminformation in subprocess so the info is always displayed (#4002) - set next release dev number (#4000) ### [dependencies] - update dependencies (#4068) - update dependencies incl. electron to v41 (#4058) - chore: upgrade ESLint to v10 and fix newly surfaced issues (#4057) - chore: update ESLint and plugins, simplify config, apply new rules (#4052) - chore: update dependencies + add exports, files, and sideEffects fields to package.json (#4040) - [core] refactor: enable ESLint rule require-await and handle detected issues (#4038) - Update node-ical and other deps (#4025) - chore: update dependencies (#4021) - chore(eslint): migrate from eslint-plugin-vitest to @vitest/eslint-plugin and run rules only on test files (#4014) - Update deps as requested by dependabot (#4008) - update Collaboration.md and dependencies (#4001) ### [logging] - refactor: further logger clean-up (#4050) - Fix Node.js v25 logging prefix and modernize logger (#4049) ### [modules/calendar] - fix(calendar): make showEnd behavior more consistent across time formats (#4059) - test(calendar): fix hardcoded date in event shape test (#4055) - [calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) - calendar.js: remove useless hasCalendarURL function (#4028) - fix(calendar): update to node-ical 0.23.1 and fix full-day recurrence lookup (#4013) - fix(calendar): correct day-of-week for full-day recurring events across all timezones (#4004) ### [modules/newsfeed] - fix(newsfeed): fix full article view and add framing check (#4039) - [newsfeed] refactor: migrate to centralized HTTPFetcher (#4023) ### [modules/weather] - fix(weather): fix openmeteo forecast stuck in the past (#4064) - fix(weather): fix weathergov forecast day labels off by one (#4065) - weather: fixes for templates (#4054) - weather: add possibility to override njk's and css (#4051) - Use getDateString in openmeteo (#4046) - [weather] refactor: migrate to server-side providers with centralized HTTPFetcher (#4032) - [weather] feat: add Weather API Provider (#4036) ### [testing] - chore: remove obsolete Jest config and unit test global setup (#4044) - replace template_spec test with config_variables test (#4034) - refactor(clientonly): modernize code structure and add comprehensive tests (#4022) - Switch to undici Agent for HTTPS requests (#4015) - chore: migrate CI workflows to ubuntu-slim for faster startup times (#4007) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <gitkraken@veeck.de> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com> Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com> Co-authored-by: Nathan <n8nyoung@gmail.com> Co-authored-by: mixasgr <mixasgr@users.noreply.github.com> Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr> Co-authored-by: Konstantinos <geraki@gmail.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: BugHaver <43462320+bughaver@users.noreply.github.com> Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com> Co-authored-by: Koen Konst <koenspero@gmail.com> Co-authored-by: Koen Konst <c.h.konst@avisi.nl> Co-authored-by: dathbe <github@beffa.us> Co-authored-by: Marcel <m-idler@users.noreply.github.com> Co-authored-by: Kevin G. <crazylegstoo@gmail.com> Co-authored-by: Jboucly <33218155+jboucly@users.noreply.github.com> Co-authored-by: Jboucly <contact@jboucly.fr> Co-authored-by: Jarno <54169345+jarnoml@users.noreply.github.com> Co-authored-by: Jordan Welch <JordanHWelch@gmail.com> Co-authored-by: Blackspirits <blackspirits@gmail.com> Co-authored-by: Samed Ozdemir <samed@xsor.io> Co-authored-by: in-voker <58696565+in-voker@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com>

Closes #4053
This started as a small fix.
After feedback and more debugging, I found more issues and inconsistencies and went a bit down the rabbit hole.
The PR is bigger now, but I think the result is better: behavior is more predictable, and the output is more consistent.
Changes
relativeanddateheaderswhenshowEndis enabled.absolute+nextDaysRelative, full-day events now keep the end date when the start is replaced by TODAY/TOMORROW/etc.absolutenow also respectshowEndsOnlyWithDuration.Before
After