diff --git a/client/src/components/Dawarich/DawarichSuggestionsPanel.tsx b/client/src/components/Dawarich/DawarichSuggestionsPanel.tsx
index 8c15ce977..622f556f5 100644
--- a/client/src/components/Dawarich/DawarichSuggestionsPanel.tsx
+++ b/client/src/components/Dawarich/DawarichSuggestionsPanel.tsx
@@ -4,6 +4,7 @@ import type { DawarichAccept, DawarichSuggestion, DawarichSuggestionTarget } fro
import { useTranslation } from '../../i18n'
import { useDawarichSuggestions } from '../../hooks/useDawarichSuggestions'
import { useTripStore } from '../../store/tripStore'
+import { useSettingsStore } from '../../store/settingsStore'
import { useIsPhone } from '../../mobile/useIsPhone'
import { relativeTime } from '../../utils/relativeTime'
import { Tooltip } from '../shared/Tooltip'
@@ -309,6 +310,9 @@ export function SuggestionRow({
onRestore?: () => void
}): React.ReactElement {
const { t, locale } = useTranslation()
+ // The traveller's own clock: these times used to come straight out of the timestamp, so
+ // a 12-hour setting got 24-hour times here and nowhere else.
+ const is12h = useSettingsStore(s => s.settings.time_format) === '12h'
return (
@@ -355,7 +359,7 @@ export function SuggestionRow({
{showDate && (
{formatDayHeading(suggestion.localDate, locale)}
)}
-
{timeRange(suggestion.startedAt, suggestion.endedAt)}
+
{timeRange(suggestion.startedAt, suggestion.endedAt, is12h)}
{formatDuration(suggestion.durationMinutes, t)}
{suggestion.state === 'accepted' && (
diff --git a/client/src/components/Dawarich/dawarichSuggestionModel.test.ts b/client/src/components/Dawarich/dawarichSuggestionModel.test.ts
index 3eb967e1a..4e49da102 100644
--- a/client/src/components/Dawarich/dawarichSuggestionModel.test.ts
+++ b/client/src/components/Dawarich/dawarichSuggestionModel.test.ts
@@ -105,12 +105,22 @@ describe('clockOf / timeRange', () => {
})
it('FE-DAWARICH-SUGMODEL-006: a range when both ends read, the arrival alone when the end does not', () => {
- expect(timeRange('2026-09-10T10:15:00+02:00', '2026-09-10T12:40:00+02:00')).toBe('10:15 – 12:40')
- expect(timeRange('2026-09-10T10:15:00+02:00', 'nonsense')).toBe('10:15')
+ expect(timeRange('2026-09-10T10:15:00+02:00', '2026-09-10T12:40:00+02:00', false)).toBe('10:15 – 12:40')
+ expect(timeRange('2026-09-10T10:15:00+02:00', 'nonsense', false)).toBe('10:15')
})
it('FE-DAWARICH-SUGMODEL-007: no arrival, no range', () => {
- expect(timeRange('nonsense', '2026-09-10T12:40:00+02:00')).toBe('')
+ expect(timeRange('nonsense', '2026-09-10T12:40:00+02:00', false)).toBe('')
+ })
+
+ it('FE-DAWARICH-SUGMODEL-012: a twelve-hour clock gets twelve-hour times, both ends of the range', () => {
+ // These were cut out of the timestamp and printed as they stood, so a traveller on a
+ // 12-hour clock read every Dawarich time in 24-hour while the rest of the app obeyed
+ // the setting.
+ expect(timeRange('2026-09-10T10:15:00+02:00', '2026-09-10T12:40:00+02:00', true)).toBe('10:15 AM – 12:40 PM')
+ expect(timeRange('2026-09-10T14:05:00+02:00', '2026-09-10T23:00:00+02:00', true)).toBe('2:05 PM – 11:00 PM')
+ // Midnight is 12 AM, not 0 AM, and noon is 12 PM.
+ expect(timeRange('2026-09-10T00:30:00+02:00', '2026-09-10T12:00:00+02:00', true)).toBe('12:30 AM – 12:00 PM')
})
})
diff --git a/client/src/components/Dawarich/dawarichSuggestionModel.ts b/client/src/components/Dawarich/dawarichSuggestionModel.ts
index eb53eec7f..dfe530969 100644
--- a/client/src/components/Dawarich/dawarichSuggestionModel.ts
+++ b/client/src/components/Dawarich/dawarichSuggestionModel.ts
@@ -1,5 +1,6 @@
import type { DawarichSuggestion } from '@trek/shared'
import { dayColor } from '../Map/dawarichTrail'
+import { formatClockTime } from '../../utils/formatters'
/**
* Pure shaping for the suggestions panel — no React, so the grouping and the
@@ -54,10 +55,15 @@ export function clockOf(iso: string): string {
*
* An en dash with hair spaces rather than a hyphen: this is a range, and it sits
* next to times often enough that the difference is visible.
+ *
+ * `is12h` is not optional on purpose. These clocks were cut straight out of the
+ * timestamp and printed, so a traveller on a 12-hour clock read every Dawarich time in
+ * 24-hour while the rest of the app obeyed the setting. A required argument makes the
+ * next caller answer the question rather than inherit the bug.
*/
-export function timeRange(startedAt: string, endedAt: string): string {
- const from = clockOf(startedAt)
- const to = clockOf(endedAt)
+export function timeRange(startedAt: string, endedAt: string, is12h: boolean): string {
+ const from = formatClockTime(clockOf(startedAt), is12h)
+ const to = formatClockTime(clockOf(endedAt), is12h)
if (!from) return ''
return to ? `${from} – ${to}` : from
}
diff --git a/client/src/components/Journey/JourneyDayDawarich.tsx b/client/src/components/Journey/JourneyDayDawarich.tsx
index ed5fae2ac..821d20b49 100644
--- a/client/src/components/Journey/JourneyDayDawarich.tsx
+++ b/client/src/components/Journey/JourneyDayDawarich.tsx
@@ -4,7 +4,8 @@ import type { DawarichSuggestion, DawarichSuggestionTarget } from '@trek/shared'
import { useTranslation } from '../../i18n'
import DawarichIcon from '../shared/DawarichIcon'
import { SuggestionRow } from '../Dawarich/DawarichSuggestionsPanel'
-import { clockOf } from '../Dawarich/dawarichSuggestionModel'
+import { timeRange } from '../Dawarich/dawarichSuggestionModel'
+import { useSettingsStore } from '../../store/settingsStore'
/**
* The stays Dawarich recorded on ONE day of the journal, folded into that day.
@@ -36,15 +37,15 @@ export default function JourneyDayDawarich({
onDismiss: (suggestion: DawarichSuggestion) => void
}): React.ReactElement | null {
const { t } = useTranslation()
+ const is12h = useSettingsStore(s => s.settings.time_format) === '12h'
const [open, setOpen] = useState(false)
if (suggestions.length === 0) return null
// From the first arrival to the last departure: what part of the day this covers, in
- // one line, so the row says something even while it is shut.
- const from = clockOf(suggestions[0]!.startedAt)
- const to = clockOf(suggestions[suggestions.length - 1]!.endedAt)
- const span = from && to ? `${from} – ${to}` : from
+ // one line, so the row says something even while it is shut. Through the same formatter
+ // the rows use, so the summary and the stays under it cannot disagree about the clock.
+ const span = timeRange(suggestions[0]!.startedAt, suggestions[suggestions.length - 1]!.endedAt, is12h)
return (