From fa739d671ad9a88b0ae4c243a00a979b8f3b92b7 Mon Sep 17 00:00:00 2001 From: Ivan Severino Date: Fri, 5 Jun 2026 15:55:22 +0200 Subject: [PATCH] Feat: show all-day events with a date-only relative label (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All-day events (e.g. holiday calendars) have no meaningful time of day, but in the default "relative" timeFormat they rendered misleading time info: today's event showed "Running", an event a few hours out showed "in 5 hours", and otherwise "Today at 12:00 AM". Render all-day events with a date-only label instead: Today / Tomorrow / weekday / configured date format, via new fullDayEventRelativeLabel(). This reuses existing infrastructure only — TODAY/TOMORROW are MagicMirror core translation keys and moment is locale-aware — so it works in every supported language with no new translation strings. Timed events are unchanged. Adds a unit test for the helper. --- MMM-GoogleCalendar.js | 34 +++++++++++++++++++++++++++- __tests__/MMM-GoogleCalendar.test.js | 17 ++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/MMM-GoogleCalendar.js b/MMM-GoogleCalendar.js index 0e38e1c..c7fce49 100644 --- a/MMM-GoogleCalendar.js +++ b/MMM-GoogleCalendar.js @@ -431,7 +431,15 @@ Module.register("MMM-GoogleCalendar", { } } else { // Show relative times - if (event.startDate >= now) { + if (event.fullDayEvent) { + // All-day events (e.g. holidays) have no meaningful time of day, + // so "at 12:00 AM", "in 5 hours" or "Running" is misleading. + // Show a date-only label instead: Today / Tomorrow / weekday / + // date. (issue #85) + timeWrapper.innerHTML = this.fullDayEventRelativeLabel( + event.startDate + ); + } else if (event.startDate >= now) { // Use relative time if (!this.config.hideTime) { timeWrapper.innerHTML = this.capFirst( @@ -1095,6 +1103,30 @@ Module.register("MMM-GoogleCalendar", { return string.charAt(0).toUpperCase() + string.slice(1); }, + /** + * Builds a date-only relative label for an all-day event (no time of day): + * Today / Tomorrow / weekday / configured date format. Used so holidays and + * other all-day events don't show misleading times such as "in 5 hours" or + * "Running" (issue #85). + * + * Relies only on existing infrastructure: TODAY/TOMORROW are MagicMirror + * core translation keys, and moment is locale-aware, so this works in every + * supported language without adding translation strings. + * + * @param {number} startDate The event start timestamp. + * @returns {string} The capitalized relative label. + */ + fullDayEventRelativeLabel: function (startDate) { + return this.capFirst( + moment(startDate).calendar(null, { + sameDay: `[${this.translate("TODAY")}]`, + nextDay: `[${this.translate("TOMORROW")}]`, + nextWeek: "dddd", + sameElse: this.config.dateFormat + }) + ); + }, + /** * Transforms the title of an event for usage. * Replaces parts of the text as defined in config.titleReplace. diff --git a/__tests__/MMM-GoogleCalendar.test.js b/__tests__/MMM-GoogleCalendar.test.js index 01a0b19..aacc580 100644 --- a/__tests__/MMM-GoogleCalendar.test.js +++ b/__tests__/MMM-GoogleCalendar.test.js @@ -156,5 +156,22 @@ describe('MMM-GoogleCalendar', () => { }); }); + describe('fullDayEventRelativeLabel', () => { + test('builds a date-only label from core TODAY/TOMORROW keys, no time (issue #85)', () => { + GCal.translate = jest.fn((key) => key); + GCal.config.dateFormat = 'MMM Do'; + + const label = GCal.fullDayEventRelativeLabel(0); + + // Returns a non-empty capitalized string (moment is mocked). + expect(typeof label).toBe('string'); + expect(label.length).toBeGreaterThan(0); + + // Uses date-only relative keys (no "at LT" time component). + expect(GCal.translate).toHaveBeenCalledWith('TODAY'); + expect(GCal.translate).toHaveBeenCalledWith('TOMORROW'); + }); + }); + // Add more describe blocks for other pure functions if identified });