PrintCalendar.tsx had three instances of the same UTC-shortcut anti-pattern:
1. Bucketing input dates via `date.split('T')[0]` — gives the UTC day
while the cell tooltip rendered local via `toLocaleDateString`. Same
data, two renderers, only one was tz-correct. Reporter on CDT (UTC-5)
saw evening prints jump to "tomorrow's" cell.
2. Per-cell lookup key built via `day.toISOString().split('T')[0]`. The
`day` Date objects produced by the calendar-generation loop are
local-tz (constructed via `new Date()` + `setDate`), so `toISOString`
shifted them back to UTC before the lookup — would have re-broken the
join even after the bucketing fix.
3. "Today" ring comparison used `new Date().toISOString().split('T')[0]`
too — at 23:00 local the ring would have moved to UTC-tomorrow's cell.
Fix adds a `localDateKey(input: string | Date): string` helper to
utils/date.ts that wraps parseUTCDate and formats via the local-tz
getters (`getFullYear` / `getMonth` / `getDate` with two-digit padding),
returning a stable comparable YYYY-MM-DD. PrintCalendar.tsx uses it in
all three spots so the buckets, the cell join, and the today ring share
the same local-tz axis as the user's tooltip label.
Backend stays UTC. Bucketing is a presentation concern and the browser
already knows the user's tz.
Stragglers flagged for follow-up: StatsPage.computeDateRange builds
dateFrom/dateTo for backend stats queries using getUTC* getters, so a
"this week" picked at 23:00 local on Sunday in CDT sends UTC-Monday-based
ranges to the backend. Fixing it properly also needs the backend to
filter on a tz-shifted UTC range, and Bambuddy has no user-tz setting
model today. localDateKey is in place for reuse when that work lands.
- Extract shared detectSystemDateFormat() helper to eliminate
duplicated system locale detection in date.ts
- Derive SUPPORTED_CURRENCIES from CURRENCY_SYMBOLS map instead
of maintaining a duplicate hardcoded list
- Consolidate redundant time-parsing regex paths into one
- Use applyTimeFormat() consistently in formatETA()
- Add exhaustive switch default for type safety
- Add formatStorageSize helper in FileManagerModal to display storage
in GB/MB instead of raw bytes
- Show "Overdue" label for queue items whose scheduled time has passed
by more than 1 minute
- Fix missing "in" prefix for English inDays translation
- Fix swapped justNow/now translations in Italian locale
- Fix whitespace formatting for waiting key across all locales
- Add trailing newline to date.ts and date.test.ts
refactor(utils): consolidate date and file size formatting
Extracts formatting logic into dedicated utility functions to improve
code maintainability and consistency across components.
Changes:
- Consolidate date formatting functions (formatRelativeTime, etc.)
- Consolidate file size formatting into single formatFileSize utility
- Fix file size calculation errors
- Update UI components to use new utilities
- Change "ASAP" to "Waiting" for unscheduled queue items
Tests:
- Add comprehensive unit tests for date utilities
- Add unit tests for file size formatting
- Add progress bar, time remaining, ETA, and layer count to currently printing item
- Remove duplicate formatDuration & formatETA functions, now imported from utils/dates
- Remove formatTime (duplicate of formatDuration)
- Update formatETA to support optional i18n translation
- Update translation: common.tomorrow
Date input for scheduled prints was swapping month and day for European
users because:
1. EU format only accepted "/" separator, not "." which is common in
European locales (e.g., "5.2.2026" for Feb 5th)
2. System format fell back to new Date() which interprets ambiguous
dates in US format
Changes:
- Added splitDateParts() helper to accept /, ., and - separators
- Updated parseDateInput() to use proper locale detection for system
format instead of relying on Date constructor
- All explicit formats (us, eu, iso) now accept any of the three
separators
Closes#233
Issue #233: Respect user date/time format in queue scheduler
- Replace native datetime-local input with custom text inputs
- Add date parsing/formatting utilities for US, EU, ISO, and system formats
- Add calendar button that opens native picker for convenience
- Pass dateFormat and timeFormat settings to ScheduleOptionsPanel
- Show format-appropriate placeholders (MM/DD/YYYY, DD/MM/YYYY, etc.)
Closes#233
- Add time format utilities to date.ts (applyTimeFormat, formatDateTime,
formatTimeOnly, TimeFormat type)
- PrintersPage: Pass timeFormat to formatETA for printer card ETA display
- ArchivesPage: Add timeFormat prop to ArchiveCard for archive timestamps
- AMSHistoryModal: Apply timeFormat to chart labels, axis ticks, and tooltip
- ProjectDetailPage: Use formatDateTime for timeline dates
- QueuePage: Pass timeFormat to formatRelativeTime for scheduled prints
- SystemInfoPage: Use formatDateTime for boot time display
- NotificationLogViewer: Apply timeFormat to notification timestamps
- Bump service worker cache version to v17
Closes#75
Problem: The backend stores timestamps in UTC, but when sending them to the frontend without timezone indicators, JavaScript interprets them inconsistently. Users saw UTC times displayed directly instead of converted to their local timezone (e.g., America/New_York).
Solution implemented:
1. Created /frontend/src/utils/date.ts with utilities:
- parseUTCDate(dateStr) - Parses backend timestamps as UTC by appending 'Z' to strings without timezone indicators
- formatDate(dateStr, options) - Formats UTC timestamps to local date/time
- formatDateOnly(dateStr, options) - Formats UTC timestamps to local date-only
2. Updated 15 frontend files to use the new utilities:
- ArchivesPage.tsx - Archive cards and list view dates
- PrintersPage.tsx - Last print date
- SettingsPage.tsx - API key last used date
- QueuePage.tsx - Scheduled print times
- ProjectDetailPage.tsx - Due dates and timeline
- ProfilesPage.tsx - Relative time display
- CalendarView.tsx - Calendar grouping by local date
- NotificationLogViewer.tsx - Log timestamps
- NotificationProviderCard.tsx - Last success date
- AMSHistoryModal.tsx - Chart data timestamps
- FilamentTrends.tsx - Usage data grouping
- PrinterQueueWidget.tsx - Queue item dates