fix: standardize date/time formats across app#84
Conversation
Create shared date formatting utility (client/src/lib/date-format.ts)
with formatDate ("Mar 6, 2026"), formatTime ("1557"), and
formatDateTime ("Mar 6, 2026 1557") functions. Update all 15 files
across client and server to use consistent formats instead of the
previous mix of locale strings, long month names, and 12h time.
https://claude.ai/code/session_01DCoGwAQxjxC5LvJTjtrbSL
|
Caution Review failedPull request was closed or merged during review No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a centralized date-formatting utility and replaces scattered inline Date/toLocale* formatting with calls to the new helpers across multiple client and server files (blog pages, admin UI, components, monitor pages, and server services). No function signatures changed. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/lib/date-format.ts`:
- Around line 4-6: The formatDate function currently calls new Date(date) which
yields epoch or Invalid Date for null/undefined; update formatDate to accept
Date | string | null | undefined (or keep signature and add runtime guards) and
return a safe fallback like "—" when date is null/undefined or when new
Date(date) is invalid; specifically, in function formatDate check for date ==
null, parse to a Date object, verify !isNaN(parsed.getTime()), and only then
call format(parsed, "MMM d, yyyy"), otherwise return the fallback.
In `@server/services/email.ts`:
- Around line 262-267: The date format string "MMM d, yyyy HHmm" is duplicated;
extract it into a shared constant (e.g., DATE_TIME_FORMAT) in a shared module
(for example `@shared/constants.ts`) and replace the literal in
server/services/email.ts where dateStr is created (the format(...) calls that
assign dateStr for plain-text and HTML lists) and in the client utility
(client/src/lib/date-format.ts) to import and use DATE_TIME_FORMAT instead so
future changes only require updating one constant.
In `@server/services/resendTracker.ts`:
- Line 1: The code re-parses SQL DATE strings with new Date(r.date) (see
variable r.date in server/services/resendTracker.ts) which treats "YYYY-MM-DD"
as UTC and can shift the displayed calendar date; replace that usage with
parseISO(r.date) from date-fns and update the import to include parseISO so
date-only values are treated as local calendar dates before passing into format
or other display logic (locate the code that does new Date(r.date) around the
Resend usage history/format call and swap it to parseISO(r.date)).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: e3340e84-6bb3-421f-9623-b91cdc5d8c6c
📒 Files selected for processing (15)
client/src/components/ApiKeysPanel.tsxclient/src/components/DeliveryLog.tsxclient/src/lib/date-format.tsclient/src/pages/AdminCampaignDetail.tsxclient/src/pages/AdminCampaigns.tsxclient/src/pages/AdminErrors.tsxclient/src/pages/Blog.tsxclient/src/pages/BlogComparison.tsxclient/src/pages/BlogPriceMonitoring.tsxclient/src/pages/BlogSelectorBreakage.tsxclient/src/pages/BlogWhyMonitorsFail.tsxclient/src/pages/MonitorDetails.tsxserver/services/browserlessTracker.tsserver/services/email.tsserver/services/resendTracker.ts
| export function formatDate(date: Date | string): string { | ||
| return format(new Date(date), "MMM d, yyyy"); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider adding null/undefined guard to prevent silent failures.
new Date(null) returns Unix epoch (Jan 1, 1970), and new Date(undefined) returns Invalid Date. Since callers may pass nullable timestamps (e.g., lastUsedAt in ApiKeysPanel), a defensive check would prevent unexpected output if the null guard is accidentally removed at call sites.
export function formatDate(date: Date | string): string {
+ if (date == null) {
+ throw new Error("formatDate received null or undefined");
+ }
return format(new Date(date), "MMM d, yyyy");
}Alternatively, update the type signature to Date | string | null | undefined and return a fallback like "—".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@client/src/lib/date-format.ts` around lines 4 - 6, The formatDate function
currently calls new Date(date) which yields epoch or Invalid Date for
null/undefined; update formatDate to accept Date | string | null | undefined (or
keep signature and add runtime guards) and return a safe fallback like "—" when
date is null/undefined or when new Date(date) is invalid; specifically, in
function formatDate check for date == null, parse to a Date object, verify
!isNaN(parsed.getTime()), and only then call format(parsed, "MMM d, yyyy"),
otherwise return the fallback.
| const dateStr = format(new Date(c.detectedAt), "MMM d, yyyy HHmm"); | ||
| return ` ${i + 1}. [${dateStr}]\n Old: ${sanitizePlainText(c.oldValue)}\n New: ${sanitizePlainText(c.newValue)}`; | ||
| }).join("\n\n"); | ||
|
|
||
| const changesHtmlList = changes.map((c) => { | ||
| const dateStr = new Date(c.detectedAt).toLocaleString("en-US"); | ||
| const dateStr = format(new Date(c.detectedAt), "MMM d, yyyy HHmm"); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Date formatting changes are safe and preserve XSS protections.
The dateStr values flow correctly through sanitizePlainText (line 263) and escapeHtml (line 270) respectively, maintaining the existing security posture.
Minor maintainability note: The format string "MMM d, yyyy HHmm" is duplicated between this server file and the new client/src/lib/date-format.ts utility. If the format ever needs to change, both locations must be updated. Consider extracting a shared constant to a @shared/ module that both client and server can import.
,
♻️ Optional: Extract shared format constant
Create a shared constant (e.g., in @shared/constants.ts):
export const DATE_TIME_FORMAT = "MMM d, yyyy HHmm";Then import and use in both locations:
-import { format } from "date-fns";
+import { format } from "date-fns";
+import { DATE_TIME_FORMAT } from "@shared/constants";-const dateStr = format(new Date(c.detectedAt), "MMM d, yyyy HHmm");
+const dateStr = format(new Date(c.detectedAt), DATE_TIME_FORMAT);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@server/services/email.ts` around lines 262 - 267, The date format string "MMM
d, yyyy HHmm" is duplicated; extract it into a shared constant (e.g.,
DATE_TIME_FORMAT) in a shared module (for example `@shared/constants.ts`) and
replace the literal in server/services/email.ts where dateStr is created (the
format(...) calls that assign dateStr for plain-text and HTML lists) and in the
client utility (client/src/lib/date-format.ts) to import and use
DATE_TIME_FORMAT instead so future changes only require updating one constant.
new Date("YYYY-MM-DD") parses as UTC midnight per ECMAScript spec,
which can render as the previous calendar day in negative-offset
timezones (US). parseISO treats date-only strings as local midnight.
https://claude.ai/code/session_01DCoGwAQxjxC5LvJTjtrbSL
Summary
client/src/lib/date-format.tsutility withformatDate("Mar 6, 2026"),formatTime("1557"), andformatDateTime("Mar 6, 2026 1557") functions using date-fnstoLocaleString(),toLocaleDateString(), long month names, and 12h timenotification.tsleft unchangedTest plan
npm run checkpasses (pre-existing TS errors in scraper.ts only)npm run test— all 1037 tests passnpm run build— production build succeedshttps://claude.ai/code/session_01DCoGwAQxjxC5LvJTjtrbSL
Summary by CodeRabbit