diff --git a/src/app/calendar-app/calendar-app.module.ts b/src/app/calendar-app/calendar-app.module.ts
index 8f8a54ce9..fa5be005d 100644
--- a/src/app/calendar-app/calendar-app.module.ts
+++ b/src/app/calendar-app/calendar-app.module.ts
@@ -60,13 +60,13 @@ import { CalendarEventCardComponent } from './calendar-event-card.component';
// See https://momentjs.com/docs/#/displaying/format/
export const MOMENT_FORMATS = {
- parseInput: 'l LT',
- fullPickerInput: 'l LT',
- datePickerInput: 'l',
- timePickerInput: 'LT',
- monthYearLabel: 'MMM YYYY',
- dateA11yLabel: 'LL',
- monthYearA11yLabel: 'MMMM YYYY',
+ parseInput: 'YYYY-MM-DD HH:mm',
+ fullPickerInput: 'YYYY-MM-DD HH:mm',
+ datePickerInput: 'YYYY-MM-DD',
+ timePickerInput: 'HH:mm',
+ monthYearLabel: 'YYYY-MM',
+ dateA11yLabel: 'YYYY-MM-DD',
+ monthYearA11yLabel: 'YYYY-MM',
};
@NgModule({
diff --git a/src/app/calendar-app/calendar-event-card.component.html b/src/app/calendar-app/calendar-event-card.component.html
index a0611c65d..b6d6c1980 100644
--- a/src/app/calendar-app/calendar-event-card.component.html
+++ b/src/app/calendar-app/calendar-event-card.component.html
@@ -9,10 +9,10 @@
Starts
Started
- {{ event.dtstart.calendar() }}
+ {{ formatDateTime(event.dtstart) }}
- Ends {{ event.dtend.calendar() }}
+ Ends {{ formatDateTime(event.dtend) }}
{{ event.recurringFrequency }} event
diff --git a/src/app/calendar-app/calendar-event-card.component.ts b/src/app/calendar-app/calendar-event-card.component.ts
index bce517620..880359348 100644
--- a/src/app/calendar-app/calendar-event-card.component.ts
+++ b/src/app/calendar-app/calendar-event-card.component.ts
@@ -18,6 +18,7 @@
// ---------- END RUNBOX LICENSE ----------
import { Component, EventEmitter, Input, Output } from '@angular/core';
+import moment from 'moment';
import { EventOverview } from './event-overview';
@Component({
@@ -31,4 +32,8 @@ export class CalendarEventCardComponent {
@Output() edit = new EventEmitter();
constructor() { }
+
+ formatDateTime(value: moment.Moment): string {
+ return value.format('YYYY-MM-DD HH:mm');
+ }
}
diff --git a/src/app/calendar-app/calendar-formatting.spec.ts b/src/app/calendar-app/calendar-formatting.spec.ts
new file mode 100644
index 000000000..f1c2c05c5
--- /dev/null
+++ b/src/app/calendar-app/calendar-formatting.spec.ts
@@ -0,0 +1,71 @@
+// --------- BEGIN RUNBOX LICENSE ---------
+// Copyright (C) 2016-2026 Runbox Solutions AS (runbox.com).
+//
+// This file is part of Runbox 7.
+//
+// Runbox 7 is free software: You can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the
+// Free Software Foundation, either version 3 of the License, or (at your
+// option) any later version.
+//
+// Runbox 7 is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Runbox 7. If not, see .
+// ---------- END RUNBOX LICENSE ----------
+
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
+import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card';
+import moment from 'moment';
+
+import { CalendarEventCardComponent } from './calendar-event-card.component';
+import { MOMENT_FORMATS } from './calendar-app.module';
+import { EventOverview } from './event-overview';
+
+describe('calendar date formatting', () => {
+ describe('date-time picker formats', () => {
+ it('uses unambiguous ISO-style date and time formats', () => {
+ expect(MOMENT_FORMATS.parseInput).toBe('YYYY-MM-DD HH:mm');
+ expect(MOMENT_FORMATS.fullPickerInput).toBe('YYYY-MM-DD HH:mm');
+ expect(MOMENT_FORMATS.datePickerInput).toBe('YYYY-MM-DD');
+ expect(MOMENT_FORMATS.timePickerInput).toBe('HH:mm');
+ });
+ });
+
+ describe('CalendarEventCardComponent', () => {
+ let component: CalendarEventCardComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [CalendarEventCardComponent],
+ imports: [
+ MatButtonModule,
+ MatCardModule,
+ ],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(CalendarEventCardComponent);
+ component = fixture.componentInstance;
+ });
+
+ it('renders event dates with ISO-style date and 24-hour time', () => {
+ component.event = new EventOverview(
+ 'Deployment window',
+ moment('2031-11-12T09:05:00'),
+ moment('2031-11-12T10:35:00'),
+ );
+
+ fixture.detectChanges();
+
+ const text = fixture.nativeElement.textContent;
+ expect(text).toContain('Starts');
+ expect(text).toContain('2031-11-12 09:05');
+ expect(text).toContain('Ends 2031-11-12 10:35');
+ });
+ });
+});