Skip to content

feat: normalize all date and time rendering to YYYY-MM-DD / HH:mm#950

Open
bassner wants to merge 3 commits into
developfrom
feat/iso-date-format
Open

feat: normalize all date and time rendering to YYYY-MM-DD / HH:mm#950
bassner wants to merge 3 commits into
developfrom
feat/iso-date-format

Conversation

@bassner

@bassner bassner commented Apr 22, 2026

Copy link
Copy Markdown
Member

Summary

Replace the inconsistent mix of locale-dependent date formats (US MM/DD/YYYY, German DD.MM.YYYY, long-form April 21, 2026, raw ISO Instant.toString()) with a single, locale-neutral, unambiguous layout everywhere a date is shown to a user:

  • Dates: YYYY-MM-DD
  • Times: HH:mm (24h)
  • Date + time (web UI / PDFs): YYYY-MM-DD HH:mm
  • Date + time (outbound emails only): YYYY-MM-DD HH:mm (ZONE) — zone suffix added because recipients may not share the server's timezone

Timezone handling is unchanged (server: ZoneId.systemDefault(), client: browser local). Only display format changes. API payloads, iCalendar (.ics), and persisted data are untouched.

What changed

Client (31 files)

  • client/src/utils/format.ts: replaced formatDate with three explicit helpers (formatDate / formatTime / formatDateTime), no options flag. Output is built from getFullYear/getMonth/getDate/getHours/getMinutes with zero-padding — fully locale-independent. Invalid Date inputs → empty string; years <1000 are zero-padded to 4 digits.
  • Every formatDate(...) call site migrated per intent (date-only vs date+time).
  • Direct toLocaleDateString / toLocaleTimeString / toLocaleString and dayjs().format(...) renderers migrated to the new helpers.
  • All Mantine DateInput and DateTimePicker instances now set valueFormat="YYYY-MM-DD" or "YYYY-MM-DD HH:mm" so pickers display (and parse typed input in) the new format.
  • Weekday / month-name label extractions and internal state keys (toDateString() / toISOString() used as map keys) are intentionally left alone.

Server (10 files, 1 new)

  • DataFormatter.formatDateyyyy-MM-dd. DataFormatter.formatDateTimeyyyy-MM-dd HH:mm (zzz) pinned to Locale.ENGLISH so German JVMs don't render MEZ/MESZ.
  • PDFBuilder.DATETIME_FORMATTERyyyy-MM-dd HH:mm (no zone suffix — internal document).
  • ThesisAnonymizationService.DATE_FORMATTER, UserDeletionService.DATE_FORMATTERyyyy-MM-dd.
  • ThesisService assessment PDF: presentation.scheduledAt now renders as date+time (previously dropped the time entirely).
  • Example strings in MailInterviewSlot / MailThesisPresentation / MailApplication templateVariables() updated so the variable-picker UI hints match actual output.
  • New Liquibase changeset 40_normalize_date_format_in_rejection_reminder.sql rewrites the inline Thymeleaf #temporals.format(app.rejectionDate, 'dd.MM.yyyy') pattern stored in the email_templates table row seeded by migration 14. Migration 14's source is left untouched so Liquibase checksums on existing deployments remain valid.
  • DataFormatterTest gains a locale-independence test that forces Locale.GERMAN + Europe/Berlin and asserts the output ends with (CET) and does not contain MEZ — this will fail if someone removes .withLocale(Locale.ENGLISH) from production.

Why

Locale-dependent rendering has led to real misunderstandings (e.g. 04/05/2026 interpreted as April 5 vs May 4). A single structurally-unambiguous format removes the ambiguity without requiring per-user locale preferences.

Test plan

  • cd client && npx tsc --noEmit — clean
  • cd client && npx eslint src/ — clean
  • cd server && ./gradlew spotlessApply test — 752 tests, 751 passed, 1 skipped (pre-existing), 0 failed
  • Playwright E2E suite
  • Manual verification: Theses table, Applications table, Presentations overview, Interview booking, Thesis page — all dates render as YYYY-MM-DD / YYYY-MM-DD HH:mm
  • Manual verification: typed YYYY-MM-DD and YYYY-MM-DD HH:mm input works in each migrated DateInput / DateTimePicker
  • Manual verification: trigger a test interview invitation and presentation invitation via Mailpit; confirm email renders 2026-04-21 14:30 (CEST) (or local zone equivalent)
  • Manual verification: download a thesis assessment PDF; confirm all dates render yyyy-MM-dd and the presentation date renders as yyyy-MM-dd HH:mm with no zone suffix

Notes

Research-group-customized email templates where someone hand-typed dd.MM.yyyy into a #temporals.format(...) call will not be auto-migrated — those would need manual re-editing. Flag in release notes if relevant.

Summary by CodeRabbit

Release Notes

  • Refactor

    • Standardized date and time display formats across the application to ISO format (YYYY-MM-DD for dates, YYYY-MM-DD HH:mm for timestamps) for improved consistency and clarity.
  • Chores

    • Updated server-side date formatting utilities and email template examples to reflect new standard date format.
    • Updated database migrations to normalize date formats in email templates.

Replace the mix of locale-dependent US (MM/DD/YYYY), German (DD.MM.YYYY)
and long-form (April 21, 2026) date formats with a single unified
ISO 8601-aligned layout everywhere a date is shown to a user — web UI,
emails, PDFs, anonymization records.

- Client: replace formatDate helper with three explicit helpers
  (formatDate / formatTime / formatDateTime), no options flag. Build
  output from getFullYear/getMonth/getDate with zero-padding, fully
  locale-independent. Guard invalid Date inputs.
- Migrate every formatDate call site plus direct toLocale* / dayjs
  renderers; classify per site as date-only vs date+time.
- Add valueFormat props to all Mantine DateInput and DateTimePicker
  instances so pickers display and parse ISO-style values.
- Server: update DataFormatter, PDFBuilder, ThesisAnonymizationService,
  UserDeletionService formatter patterns. Email DataFormatter uses
  "yyyy-MM-dd HH:mm (zzz)" pinned to Locale.ENGLISH so German JVMs
  don't render MEZ/MESZ. PDFs use "yyyy-MM-dd HH:mm" with no zone suffix.
- ThesisService assessment PDF: render presentation scheduledAt as
  date+time (previously dropped the time).
- New Liquibase changeset 40 rewrites the inline Thymeleaf
  #temporals.format pattern in the rejection-reminder email template
  row. Migration 14 source left untouched to preserve checksum.
- DataFormatterTest gains a locale-independence test that forces a
  German default locale and asserts CET (English) output.
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@krusche, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 48 minutes and 15 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 99518669-cd8c-4b00-93d0-3feacc0c7fc5

📥 Commits

Reviewing files that changed from the base of the PR and between 4104de3 and 0fa9fd8.

📒 Files selected for processing (28)
  • client/src/components/ApplicationData/ApplicationData.tsx
  • client/src/components/ApplicationReviewForm/ApplicationReviewForm.tsx
  • client/src/components/ApplicationsTable/ApplicationsTable.tsx
  • client/src/components/InterviewSlotInformation/InterviewSlotInformation.tsx
  • client/src/components/PresentationsTable/PresentationsTable.tsx
  • client/src/components/PresentationsTable/components/ReplacePresentationModal/ReplacePresentationModal.tsx
  • client/src/components/ThesesGanttChart/ThesesGanttChart.tsx
  • client/src/components/ThesesTable/ThesesTable.tsx
  • client/src/components/ThesisCommentsList/components/ThesisCommentElement.tsx
  • client/src/components/ThesisData/ThesisData.tsx
  • client/src/components/TopicData/TopicData.tsx
  • client/src/components/TopicsTable/TopicsTable.tsx
  • client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/SlotItem.tsx
  • client/src/pages/ManageTopicsPage/components/ReplaceTopicModal/ReplaceTopicModal.tsx
  • client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx
  • client/src/pages/PresentationPage/PresentationPage.tsx
  • client/src/pages/ReplaceApplicationPage/components/MotivationStep/MotivationStep.tsx
  • client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/components/CollapsibleTopicElement.tsx
  • client/src/pages/SettingsPage/components/AccountDeletion/AccountDeletion.tsx
  • client/src/pages/SettingsPage/components/DataExport/DataExport.tsx
  • client/src/pages/ThesisPage/components/FileHistoryTable/FileHistoryTable.tsx
  • client/src/pages/ThesisPage/components/ThesisConfigSection/ThesisConfigSection.tsx
  • client/src/pages/ThesisPage/components/ThesisFeedbackOverview/ThesisFeedbackOverview.tsx
  • client/src/pages/ThesisPage/components/ThesisPresentationSection/components/PresentationCard.tsx
  • client/src/pages/ThesisPage/components/ThesisWritingSection/ThesisWritingSection.tsx
  • client/src/utils/format.ts

Walkthrough

This pull request standardizes date and time formatting across the application by replacing locale-based formatting (e.g., .toLocaleDateString(), dd.MM.yyyy) with consistent ISO-like formats (YYYY-MM-DD, YYYY-MM-DD HH:mm, HH:mm). Changes affect ~35 files across client components, server utilities, mail templates, and database migrations.

Changes

Cohort / File(s) Summary
Date/Time Utility Updates
client/src/utils/format.ts, server/src/main/java/de/tum/cit/aet/thesis/utility/DataFormatter.java
Core formatting functions refactored: formatDate now returns YYYY-MM-DD, added new formatTime (HH:mm) and formatDateTime (YYYY-MM-DD HH:mm) exports. Server DataFormatter patterns updated from locale-dependent to fixed ISO-like formats with English locale enforcement.
Client Application Components
client/src/components/ApplicationData/ApplicationData.tsx, client/src/components/ApplicationReviewForm/ApplicationReviewForm.tsx, client/src/components/ApplicationsTable/ApplicationsTable.tsx
Replaced formatDate(date, { withTime: true }) with formatDateTime() for timestamps; removed explicit withTime option for date-only fields.
Client Interview & Presentation Components
client/src/components/InterviewSlotInformation/InterviewSlotInformation.tsx, client/src/components/PresentationsTable/PresentationsTable.tsx, client/src/components/ThesesGanttChart/ThesesGanttChart.tsx
Updated to use formatDateTime() for scheduled/presentation timestamps; replaced inline .toLocaleString() and .toLocaleDateString() calls with utility functions.
Client Table & Data Display Components
client/src/components/ThesesTable/ThesesTable.tsx, client/src/components/ThesisCommentsList/.../ThesisCommentElement.tsx, client/src/components/ThesisData/ThesisData.tsx, client/src/components/TopicsTable/TopicsTable.tsx, client/src/components/TopicData/TopicData.tsx
Removed { withTime: false } options from formatDate() calls; replaced formatDate(date, { withTime: true }) with formatDateTime().
Client Page Components & Modals
client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx, client/src/pages/InterviewTopicOverviewPage/components/SlotItem.tsx, client/src/pages/.../CollapsibleTopicElement.tsx, client/src/pages/ReplaceApplicationPage/.../MotivationStep.tsx, client/src/pages/SettingsPage/components/.../*
Replaced .toLocaleTimeString(), .toLocaleDateString() with formatTime() and formatDate() calls; added valueFormat='YYYY-MM-DD' and valueFormat='YYYY-MM-DD HH:mm' to Mantine date/time input components.
Client Date Format Changes
client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx, client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx
Changed dayjs().format('MMM D, YYYY') to dayjs().format('YYYY-MM-DD') for consistent date display across UI.
Client Thesis & Presentation Components
client/src/pages/ThesisPage/components/FileHistoryTable/FileHistoryTable.tsx, client/src/pages/ThesisPage/components/ThesisFeedbackOverview/ThesisFeedbackOverview.tsx, client/src/pages/ThesisPage/components/.../PresentationCard.tsx, client/src/pages/ThesisPage/components/ThesisWritingSection/ThesisWritingSection.tsx, client/src/pages/ThesisPage/components/ThesisConfigSection/ThesisConfigSection.tsx, client/src/pages/PresentationPage/PresentationPage.tsx, client/src/pages/TopicPage/components/DateItemAdditionalInformation.tsx
Updated presentation/thesis date fields to use formatDateTime() where timestamps are needed; added explicit valueFormat attributes to Mantine inputs.
Server Mail Template Variables
server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailApplication.java, server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailInterviewSlot.java, server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailThesisPresentation.java
Updated example placeholder values in mail template variable descriptors to reflect new date/time format (e.g., 01.10.20242024-10-01).
Server Service & Utility Updates
server/src/main/java/de/tum/cit/aet/thesis/service/ThesisAnonymizationService.java, server/src/main/java/de/tum/cit/aet/thesis/service/ThesisService.java, server/src/main/java/de/tum/cit/aet/thesis/service/UserDeletionService.java, server/src/main/java/de/tum/cit/aet/thesis/utility/PDFBuilder.java
Updated static DATE_FORMATTER and DATETIME_FORMATTER patterns to ISO-like formats (yyyy-MM-dd, yyyy-MM-dd HH:mm); changed DataFormatter calls from formatDate() to formatDateTime() where timestamps are needed.
Server Database Migrations
server/src/main/resources/db/changelog/changes/40_normalize_date_format_in_rejection_reminder.sql, server/src/main/resources/db/changelog/db.changelog-master.xml
Added Liquibase migration to update email template placeholders from dd.MM.yyyy to yyyy-MM-dd format in existing database records.
Server Tests
server/src/test/java/de/tum/cit/aet/thesis/utility/DataFormatterTest.java
Updated test assertions for formatDate() and formatDateTime() to expect new ISO-like patterns; added locale-independence test for formatDateTime() to verify English timezone abbreviations regardless of JVM defaults.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main objective: normalizing date and time rendering across the codebase to consistent ISO-like formats (YYYY-MM-DD and HH:mm).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/iso-date-format

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
server/src/main/resources/db/changelog/changes/40_normalize_date_format_in_rejection_reminder.sql (1)

4-9: Restrict the migration to rows that contain the legacy pattern.

As written, every email_templates row is updated/locked even when body_html does not contain the old formatter. Add a WHERE clause to avoid unnecessary writes and trigger/audit side effects.

♻️ Proposed SQL refinement
 UPDATE email_templates
 SET body_html = REPLACE(
   body_html,
   '#temporals.format(app.rejectionDate, ''dd.MM.yyyy'')',
   '#temporals.format(app.rejectionDate, ''yyyy-MM-dd'')'
-);
+)
+WHERE body_html LIKE '%#temporals.format(app.rejectionDate, ''dd.MM.yyyy'')%';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@server/src/main/resources/db/changelog/changes/40_normalize_date_format_in_rejection_reminder.sql`
around lines 4 - 9, The UPDATE currently writes every row in the email_templates
table; restrict it to only rows that contain the legacy formatter by adding a
WHERE clause that checks body_html for the exact legacy pattern (e.g., using
LIKE '%#temporals.format(app.rejectionDate, ''dd.MM.yyyy'')%') so only rows with
that substring are updated and avoid unnecessary writes/triggers/audit entries.
server/src/main/java/de/tum/cit/aet/thesis/utility/DataFormatter.java (1)

23-50: Optional: cache formatters as static constants.

formatDate and formatDateTime allocate a fresh DateTimeFormatter on every call. Since DateTimeFormatter is thread-safe and immutable, hoisting both into private static final fields is a cheap win on hot paths (PDF/email rendering loops).

♻️ Proposed refactor
+	private static final DateTimeFormatter DATE_FORMATTER =
+			DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.systemDefault());
+
+	private static final DateTimeFormatter DATE_TIME_FORMATTER =
+			DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm (zzz)")
+					.withLocale(Locale.ENGLISH)
+					.withZone(ZoneId.systemDefault());
+
 	public static String formatDate(Object time) {
 		if (!(time instanceof Instant)) {
 			return "";
 		}
-
-		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
-				.withZone(ZoneId.systemDefault());
-
-		return formatter.format((Instant) time);
+		return DATE_FORMATTER.format((Instant) time);
 	}

Note: caching locks ZoneId.systemDefault() at class-load time. If the server's default zone can change at runtime (unusual), keep the current per-call construction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/src/main/java/de/tum/cit/aet/thesis/utility/DataFormatter.java` around
lines 23 - 50, formatDate and formatDateTime currently create a new
DateTimeFormatter per call; hoist these into private static final constants
(e.g., DATE_FORMATTER and DATETIME_FORMATTER) and reuse them in the methods to
avoid repeated allocations, ensuring you initialize them with the same patterns,
Locale.ENGLISH for the datetime formatter, and withZone(ZoneId.systemDefault())
at class load time (leave per-call construction if your runtime may change
default ZoneId). Update formatDate and formatDateTime to call
DATE_FORMATTER.format((Instant) time) and DATETIME_FORMATTER.format((Instant)
time) respectively.
client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx (1)

260-260: Render the normalized date key directly.

date is already created as YYYY-MM-DD, so the extra formatting pass is redundant and can be avoided.

♻️ Proposed simplification
-                          <Title order={5}>{dayjs(date).format('YYYY-MM-DD')}</Title>
+                          <Title order={5}>{date}</Title>
...
-                      <Divider label={dayjs(date).format('YYYY-MM-DD')} data-date={date} />
+                      <Divider label={date} data-date={date} />

Also applies to: 315-315

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx` at
line 260, The Title rendering is re-formatting a date string that's already
normalized to "YYYY-MM-DD"; change the JSX in PresentationOverviewPage where
<Title order={5}>{dayjs(date).format('YYYY-MM-DD')}</Title> (and the similar
occurrence around the 315 region) to render the normalized date variable
directly as <Title order={5}>{date}</Title>, removing the redundant dayjs
formatting call.
client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx (1)

299-299: Use formatDate helper for consistency with the rest of the PR.

This is the lone holdout still routed through dayjs(...).format('YYYY-MM-DD'). The whole point of this PR is to centralize date rendering via formatDate so future format tweaks land in one place. Might as well let this one join the party.

♻️ Proposed change
-import dayjs from 'dayjs'
+import { formatDate } from '../../../utils/format'
@@
-              <Title order={6}>{dayjs(date).format('YYYY-MM-DD')}</Title>
+              <Title order={6}>{formatDate(date)}</Title>

(Drop the dayjs import if no longer used elsewhere in the file.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx`
at line 299, Replace the direct dayjs formatting in the CollapsibleDateCard
component — specifically the Title rendering currently using
dayjs(date).format('YYYY-MM-DD') — with the shared formatDate helper (e.g.,
Title order={6}>{formatDate(date)}</Title>) to centralize date rendering; after
changing the Title, remove the dayjs import from the file if no other code
references it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/src/utils/format.ts`:
- Around line 17-50: The toValidDate routine is susceptible to timezone shifts
for date-only strings like "YYYY-MM-DD"; update toValidDate to detect an ISO
date-only pattern (e.g., /^\d{4}-\d{2}-\d{2}$/), parse year/month/day by
splitting the string, create a local Date via new Date() then setFullYear(year,
monthIndex, day) and setHours(0,0,0,0) so it represents midnight local time,
validate that the constructed Date's year/month/day match the parsed values and
return null on mismatch or invalid input; leave handling of other string formats
and Date instances unchanged so formatDate, formatTime and formatDateTime
continue to use toValidDate safely.

In `@server/src/main/java/de/tum/cit/aet/thesis/service/ThesisService.java`:
- Line 767: Replace the timezone-inclusive call in ThesisService
(builder.addOverviewItem("Presentation Date",
DataFormatter.formatDateTime(presentation.getScheduledAt()))) with a PDF-style
no-zone formatter: either add a new public helper on DataFormatter (e.g.,
DataFormatter.formatDateTimeForPdf or similar) that formats using the pattern
"yyyy-MM-dd HH:mm" and call that from ThesisService, or apply
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") directly to
presentation.getScheduledAt() in ThesisService to match the formatting used by
PDFBuilder; ensure the new method (if added) is public and used for all PDF
output to keep behavior consistent.

In `@server/src/test/java/de/tum/cit/aet/thesis/utility/DataFormatterTest.java`:
- Around line 89-108: The test formatDateTime_IsLocaleIndependent mutates
JVM-global Locale/TimeZone which breaks test isolation; update the test to avoid
changing globals by either invoking DataFormatter.formatDateTime in a way that
supplies a deterministic locale/time-zone (e.g., use an overload or helper on
DataFormatter that accepts a Locale/ZoneId or Clock) or annotate the test with
`@ResourceLock`(Resources.LOCALE) and `@ResourceLock`(Resources.TIME_ZONE) to
serialize access; also replace JUnit assertions (assertTrue/assertFalse) with
AssertJ assertions (assertThat(...).endsWith("(CET)") and
assertThat(...).doesNotContain("MEZ")) and keep restoring any originals if you
must touch globals.

---

Nitpick comments:
In
`@client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx`:
- Line 299: Replace the direct dayjs formatting in the CollapsibleDateCard
component — specifically the Title rendering currently using
dayjs(date).format('YYYY-MM-DD') — with the shared formatDate helper (e.g.,
Title order={6}>{formatDate(date)}</Title>) to centralize date rendering; after
changing the Title, remove the dayjs import from the file if no other code
references it.

In `@client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx`:
- Line 260: The Title rendering is re-formatting a date string that's already
normalized to "YYYY-MM-DD"; change the JSX in PresentationOverviewPage where
<Title order={5}>{dayjs(date).format('YYYY-MM-DD')}</Title> (and the similar
occurrence around the 315 region) to render the normalized date variable
directly as <Title order={5}>{date}</Title>, removing the redundant dayjs
formatting call.

In `@server/src/main/java/de/tum/cit/aet/thesis/utility/DataFormatter.java`:
- Around line 23-50: formatDate and formatDateTime currently create a new
DateTimeFormatter per call; hoist these into private static final constants
(e.g., DATE_FORMATTER and DATETIME_FORMATTER) and reuse them in the methods to
avoid repeated allocations, ensuring you initialize them with the same patterns,
Locale.ENGLISH for the datetime formatter, and withZone(ZoneId.systemDefault())
at class load time (leave per-call construction if your runtime may change
default ZoneId). Update formatDate and formatDateTime to call
DATE_FORMATTER.format((Instant) time) and DATETIME_FORMATTER.format((Instant)
time) respectively.

In
`@server/src/main/resources/db/changelog/changes/40_normalize_date_format_in_rejection_reminder.sql`:
- Around line 4-9: The UPDATE currently writes every row in the email_templates
table; restrict it to only rows that contain the legacy formatter by adding a
WHERE clause that checks body_html for the exact legacy pattern (e.g., using
LIKE '%#temporals.format(app.rejectionDate, ''dd.MM.yyyy'')%') so only rows with
that substring are updated and avoid unnecessary writes/triggers/audit entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c763bb56-1075-468b-88f7-e95015ce0d16

📥 Commits

Reviewing files that changed from the base of the PR and between bec3855 and 4104de3.

📒 Files selected for processing (41)
  • client/src/components/ApplicationData/ApplicationData.tsx
  • client/src/components/ApplicationReviewForm/ApplicationReviewForm.tsx
  • client/src/components/ApplicationsTable/ApplicationsTable.tsx
  • client/src/components/GanttChart/components/GanttChartRangeSlider/GanttChartRangeSlider.tsx
  • client/src/components/InterviewSlotInformation/InterviewSlotInformation.tsx
  • client/src/components/PresentationsTable/PresentationsTable.tsx
  • client/src/components/PresentationsTable/components/ReplacePresentationModal/ReplacePresentationModal.tsx
  • client/src/components/ThesesGanttChart/ThesesGanttChart.tsx
  • client/src/components/ThesesTable/ThesesTable.tsx
  • client/src/components/ThesisCommentsList/components/ThesisCommentElement.tsx
  • client/src/components/ThesisData/ThesisData.tsx
  • client/src/components/TopicData/TopicData.tsx
  • client/src/components/TopicsTable/TopicsTable.tsx
  • client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/SlotItem.tsx
  • client/src/pages/ManageTopicsPage/components/ReplaceTopicModal/ReplaceTopicModal.tsx
  • client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx
  • client/src/pages/PresentationPage/PresentationPage.tsx
  • client/src/pages/ReplaceApplicationPage/components/MotivationStep/MotivationStep.tsx
  • client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/components/CollapsibleTopicElement.tsx
  • client/src/pages/SettingsPage/components/AccountDeletion/AccountDeletion.tsx
  • client/src/pages/SettingsPage/components/DataExport/DataExport.tsx
  • client/src/pages/ThesisPage/components/FileHistoryTable/FileHistoryTable.tsx
  • client/src/pages/ThesisPage/components/ThesisConfigSection/ThesisConfigSection.tsx
  • client/src/pages/ThesisPage/components/ThesisFeedbackOverview/ThesisFeedbackOverview.tsx
  • client/src/pages/ThesisPage/components/ThesisPresentationSection/components/PresentationCard.tsx
  • client/src/pages/ThesisPage/components/ThesisWritingSection/ThesisWritingSection.tsx
  • client/src/pages/TopicPage/components/DateItemAdditonalInformation.tsx
  • client/src/utils/format.ts
  • server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailApplication.java
  • server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailInterviewSlot.java
  • server/src/main/java/de/tum/cit/aet/thesis/mailvariables/MailThesisPresentation.java
  • server/src/main/java/de/tum/cit/aet/thesis/service/ThesisAnonymizationService.java
  • server/src/main/java/de/tum/cit/aet/thesis/service/ThesisService.java
  • server/src/main/java/de/tum/cit/aet/thesis/service/UserDeletionService.java
  • server/src/main/java/de/tum/cit/aet/thesis/utility/DataFormatter.java
  • server/src/main/java/de/tum/cit/aet/thesis/utility/PDFBuilder.java
  • server/src/main/resources/db/changelog/changes/40_normalize_date_format_in_rejection_reminder.sql
  • server/src/main/resources/db/changelog/db.changelog-master.xml
  • server/src/test/java/de/tum/cit/aet/thesis/utility/DataFormatterTest.java

Comment thread client/src/utils/format.ts
Comment thread server/src/main/java/de/tum/cit/aet/thesis/service/ThesisService.java Outdated
- client format.ts: parse YYYY-MM-DD date-only strings as local
  midnight, not UTC midnight, to avoid off-by-one day shifts in
  negative UTC-offset browsers.
- DataFormatter: add formatDateTimeWithoutZone() for PDF/internal
  contexts; ThesisService PDF presentation date now uses it so the
  assessment PDF stays zone-free and matches PDFBuilder's convention.
- Liquibase changeset 40: add WHERE clause so only rows that contain
  the legacy pattern are updated; avoids unnecessary writes and audit
  noise.
- PresentationOverviewPage: render the pre-normalized YYYY-MM-DD map
  key directly instead of re-formatting with dayjs.
- CollapsibleDateCard: replace the last dayjs-based date render with
  the shared formatDate helper; drop the now-unused dayjs import.
- DataFormatterTest: use AssertJ assertions and annotate the
  locale-independence test with @ResourceLock(LOCALE / TIME_ZONE)
  so parallel test execution cannot bleed JVM-global state.

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bassner Clean, thorough normalization across the full stack. The timezone-safe parsing for date-only strings and the locale-pinned zone abbreviations are nice touches. Good call adding the Liquibase migration for the stored template rather than editing the original changeset.

# Conflicts:
#	client/src/components/PresentationsTable/PresentationsTable.tsx
#	client/src/components/TopicsTable/TopicsTable.tsx
#	client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx
#	client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx
#	client/src/utils/format.ts

@Claudia-Anthropica Claudia-Anthropica left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bassner Re-reviewing after the develop merge. The date normalization itself is unchanged from what I approved and still looks great, and CodeRabbit's earlier points are all addressed. The blocker is purely a merge artifact: the merge pulled in the #966 guard test (client/test/format.test.mjs) whose formatDate — issue #827 block pins the old dateStyle: 'medium' implementation and now reds run-tests / build — see inline. Minor aside: ApplicationListItem.tsx ('Submission Date', createdAt) and ThesisPage.tsx (anonymizedAt) weren't touched, so they silently dropped their time when formatDate's default flipped from withTime: true to date-only — the former now disagrees with ApplicationData.tsx, which shows the same field with time. Worth a quick look if that divergence isn't intended.

return item
}

export function formatDate(date: string | Date | null | undefined): string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bassner [high] The develop merge dragged in client/test/format.test.mjs (the #966 guard test), and its formatDate — issue #827 describe block pins the old implementation — it reads this very source file and asserts dateStyle: 'medium' is present plus the withTime ? { timeStyle: 'short' } : {} gate. Since you replaced all of that with the manual ISO builder, the node --test test/*.test.mjs step fails and reds run-tests / build. That whole describe block needs rewriting for the new format (the ensureAbsoluteLinkHref block below it is fine and should stay).

🤖 Prompt for AI agents

In client/test/format.test.mjs, the describe('formatDate — issue #827 ...') block (roughly lines 14-99) pins the obsolete dateStyle: 'medium' implementation and fails because client/src/utils/format.ts no longer uses toLocaleString. Rewrite that block to match the new helpers: assert formatDate(...) yields YYYY-MM-DD, formatTime(...) yields HH:mm, and formatDateTime(...) yields YYYY-MM-DD HH:mm, and replace the source-pinning assertions (/dateStyle:\s*'medium'/, the withTime ternary regex) with checks for the new pad/getFullYear-based implementation. Leave the ensureAbsoluteLinkHref describe block untouched. Verify with cd client && node --test test/*.test.mjs.

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.

3 participants