use iso & utc dates
Asrc/lib/formatDate.ts
| @@ -0,0 +1,32 @@ | |||
|---|---|---|---|
| 1 | + | export function formatDate(iso: string): string { | |
| 2 | + | try { | |
| 3 | + | return new Intl.DateTimeFormat("en-CA", { | |
| 4 | + | timeZone: "UTC", | |
| 5 | + | year: "numeric", | |
| 6 | + | month: "2-digit", | |
| 7 | + | day: "2-digit", | |
| 8 | + | }).format(new Date(iso)); | |
| 9 | + | } catch { | |
| 10 | + | return iso; | |
| 11 | + | } | |
| 12 | + | } | |
| 13 | + | ||
| 14 | + | export function formatDateTime(iso: string): string { | |
| 15 | + | try { | |
| 16 | + | const parts = new Intl.DateTimeFormat("en-CA", { | |
| 17 | + | timeZone: "UTC", | |
| 18 | + | year: "numeric", | |
| 19 | + | month: "2-digit", | |
| 20 | + | day: "2-digit", | |
| 21 | + | hour: "2-digit", | |
| 22 | + | minute: "2-digit", | |
| 23 | + | second: "2-digit", | |
| 24 | + | hour12: false, | |
| 25 | + | }).formatToParts(new Date(iso)); | |
| 26 | + | const get = (type: string) => | |
| 27 | + | parts.find((p) => p.type === type)?.value ?? ""; | |
| 28 | + | return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}:${get("second")} UTC`; | |
| 29 | + | } catch { | |
| 30 | + | return iso; | |
| 31 | + | } | |
| 32 | + | } | |
Msrc/views/DateWithEdited.tsx
| @@ -1,3 +1,5 @@ | |||
|---|---|---|---|
| 1 | + | import { formatDate, formatDateTime } from "../lib/formatDate.ts"; | |
| 2 | + | ||
| 1 | 3 | export function DateWithEdited({ | |
| 2 | 4 | date, | |
| 3 | 5 | editedAt, | |
| @@ -5,13 +7,13 @@ export function DateWithEdited({ | |||
|---|---|---|---|
| 5 | 7 | date: string; | |
| 6 | 8 | editedAt: string | null; | |
| 7 | 9 | }) { | |
| 8 | - | const label = new Date(date).toLocaleDateString(); | |
| 10 | + | const label = formatDate(date); | |
| 9 | 11 | if (!editedAt) return <time datetime={date}>{label}</time>; | |
| 10 | 12 | return ( | |
| 11 | 13 | <time | |
| 12 | 14 | datetime={date} | |
| 13 | 15 | class="edited-indicator" | |
| 14 | - | title={`Edited ${new Date(editedAt).toLocaleString()}`} | |
| 16 | + | title={`Edited ${formatDateTime(editedAt)}`} | |
| 15 | 17 | > | |
| 16 | 18 | *{label} | |
| 17 | 19 | </time> | |
Msrc/views/Settings.tsx
| @@ -1,3 +1,4 @@ | |||
|---|---|---|---|
| 1 | + | import { formatDate } from "../lib/formatDate.ts"; | |
| 1 | 2 | import type { SessionUser } from "../middleware/session.ts"; | |
| 2 | 3 | import { Avatar } from "./Avatar.tsx"; | |
| 3 | 4 | import { Layout } from "./layout.tsx"; | |
| @@ -283,9 +284,7 @@ export function Settings({ | |||
|---|---|---|---|
| 283 | 284 | <div class="passkey-item"> | |
| 284 | 285 | <span class="passkey-date"> | |
| 285 | 286 | Added{" "} | |
| 286 | - | {new Date( | |
| 287 | - | pk.created_at, | |
| 288 | - | ).toLocaleDateString()} | |
| 287 | + | {formatDate(pk.created_at)} | |
| 289 | 288 | </span> | |
| 290 | 289 | <form | |
| 291 | 290 | method="POST" | |
| @@ -352,9 +351,7 @@ export function Settings({ | |||
|---|---|---|---|
| 352 | 351 | </span> | |
| 353 | 352 | <span class="passkey-date"> | |
| 354 | 353 | Added{" "} | |
| 355 | - | {new Date( | |
| 356 | - | key.created_at, | |
| 357 | - | ).toLocaleDateString()} | |
| 354 | + | {formatDate(key.created_at)} | |
| 358 | 355 | </span> | |
| 359 | 356 | </div> | |
| 360 | 357 | <form | |
Msrc/views/issues/IssueList.tsx
| @@ -1,4 +1,5 @@ | |||
|---|---|---|---|
| 1 | 1 | import type { IssueRow, RepositoryRow } from "../../db/index.ts"; | |
| 2 | + | import { formatDate } from "../../lib/formatDate.ts"; | |
| 2 | 3 | import { displayName } from "../../lib/users.ts"; | |
| 3 | 4 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 4 | 5 | import { Avatar } from "../Avatar.tsx"; | |
| @@ -106,9 +107,7 @@ export function IssueList({ | |||
|---|---|---|---|
| 106 | 107 | {displayName(issue.author_username)} | |
| 107 | 108 | </span> | |
| 108 | 109 | <time datetime={issue.created_at}> | |
| 109 | - | {new Date( | |
| 110 | - | issue.created_at, | |
| 111 | - | ).toLocaleDateString()} | |
| 110 | + | {formatDate(issue.created_at)} | |
| 112 | 111 | </time> | |
| 113 | 112 | </div> | |
| 114 | 113 | </li> | |
Msrc/views/patches/PatchList.tsx
| @@ -1,4 +1,5 @@ | |||
|---|---|---|---|
| 1 | 1 | import type { PatchRow, RepositoryRow } from "../../db/index.ts"; | |
| 2 | + | import { formatDate } from "../../lib/formatDate.ts"; | |
| 2 | 3 | import { displayName } from "../../lib/users.ts"; | |
| 3 | 4 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 4 | 5 | import { Avatar } from "../Avatar.tsx"; | |
| @@ -103,9 +104,7 @@ export function PatchList({ | |||
|---|---|---|---|
| 103 | 104 | by {displayName(patch.author_username)} | |
| 104 | 105 | </span> | |
| 105 | 106 | <time datetime={patch.created_at}> | |
| 106 | - | {new Date( | |
| 107 | - | patch.created_at, | |
| 108 | - | ).toLocaleDateString()} | |
| 107 | + | {formatDate(patch.created_at)} | |
| 109 | 108 | </time> | |
| 110 | 109 | </div> | |
| 111 | 110 | </li> | |
Msrc/views/releases/ReleaseDetail.tsx
| @@ -3,6 +3,7 @@ import type { | |||
|---|---|---|---|
| 3 | 3 | ReleaseRow, | |
| 4 | 4 | RepositoryRow, | |
| 5 | 5 | } from "../../db/index.ts"; | |
| 6 | + | import { formatDate } from "../../lib/formatDate.ts"; | |
| 6 | 7 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 7 | 8 | import { Layout } from "../layout.tsx"; | |
| 8 | 9 | import { RepoHeader } from "../repos/RepoHeader.tsx"; | |
| @@ -72,9 +73,7 @@ export function ReleaseDetail({ | |||
|---|---|---|---|
| 72 | 73 | <div class="release-item-date"> | |
| 73 | 74 | <span class="badge">{release.tag_name}</span> | |
| 74 | 75 | <time datetime={release.created_at}> | |
| 75 | - | {new Date( | |
| 76 | - | release.created_at, | |
| 77 | - | ).toLocaleDateString()} | |
| 76 | + | {formatDate(release.created_at)} | |
| 78 | 77 | </time> | |
| 79 | 78 | </div> | |
| 80 | 79 | </div> | |
Msrc/views/releases/ReleaseList.tsx
| @@ -1,4 +1,5 @@ | |||
|---|---|---|---|
| 1 | 1 | import type { ReleaseRow, RepositoryRow } from "../../db/index.ts"; | |
| 2 | + | import { formatDate } from "../../lib/formatDate.ts"; | |
| 2 | 3 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 3 | 4 | import { | |
| 4 | 5 | markdownToPlaintext, | |
| @@ -97,9 +98,7 @@ export function ReleaseList({ | |||
|---|---|---|---|
| 97 | 98 | {release.tag_name} | |
| 98 | 99 | </span> | |
| 99 | 100 | <time datetime={release.created_at}> | |
| 100 | - | {new Date( | |
| 101 | - | release.created_at, | |
| 102 | - | ).toLocaleDateString()} | |
| 101 | + | {formatDate(release.created_at)} | |
| 103 | 102 | </time> | |
| 104 | 103 | </div> | |
| 105 | 104 | </div> | |
Msrc/views/repos/CommitDetail.tsx
| @@ -1,5 +1,6 @@ | |||
|---|---|---|---|
| 1 | 1 | import { escapeHtml } from "@kitajs/html"; | |
| 2 | 2 | import type { RepositoryRow } from "../../db/index.ts"; | |
| 3 | + | import { formatDateTime } from "../../lib/formatDate.ts"; | |
| 3 | 4 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 4 | 5 | import type { RenderedDiffFile } from "../../services/diffHighlight.ts"; | |
| 5 | 6 | import type { CommitMeta } from "../../services/git.ts"; | |
| @@ -16,17 +17,6 @@ interface CommitDetailProps { | |||
|---|---|---|---|
| 16 | 17 | files: RenderedDiffFile[]; | |
| 17 | 18 | } | |
| 18 | 19 | ||
| 19 | - | function formatDate(iso: string): string { | |
| 20 | - | try { | |
| 21 | - | return new Date(iso).toLocaleString(undefined, { | |
| 22 | - | dateStyle: "medium", | |
| 23 | - | timeStyle: "short", | |
| 24 | - | }); | |
| 25 | - | } catch { | |
| 26 | - | return iso; | |
| 27 | - | } | |
| 28 | - | } | |
| 29 | - | ||
| 30 | 20 | export function CommitDetail({ | |
| 31 | 21 | user, | |
| 32 | 22 | repo, | |
| @@ -76,7 +66,7 @@ export function CommitDetail({ | |||
|---|---|---|---|
| 76 | 66 | class="commit-meta-value" | |
| 77 | 67 | datetime={meta.date} | |
| 78 | 68 | > | |
| 79 | - | {formatDate(meta.date)} | |
| 69 | + | {formatDateTime(meta.date)} | |
| 80 | 70 | </time> | |
| 81 | 71 | </div> | |
| 82 | 72 | {(meta.committer !== meta.author || | |
| @@ -100,7 +90,7 @@ export function CommitDetail({ | |||
|---|---|---|---|
| 100 | 90 | class="commit-meta-value" | |
| 101 | 91 | datetime={meta.committerDate} | |
| 102 | 92 | > | |
| 103 | - | {formatDate(meta.committerDate)} | |
| 93 | + | {formatDateTime(meta.committerDate)} | |
| 104 | 94 | </time> | |
| 105 | 95 | </div> | |
| 106 | 96 | </> | |
Msrc/views/repos/CommitLog.tsx
| @@ -1,4 +1,6 @@ | |||
|---|---|---|---|
| 1 | 1 | import type { RepositoryRow } from "../../db/index.ts"; | |
| 2 | + | import { formatDateTime } from "../../lib/formatDate.ts"; | |
| 3 | + | ||
| 2 | 4 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 3 | 5 | import type { CommitEntry } from "../../services/git.ts"; | |
| 4 | 6 | import { Layout } from "../layout.tsx"; | |
| @@ -66,7 +68,7 @@ export function CommitLog({ | |||
|---|---|---|---|
| 66 | 68 | {c.hash.slice(0, 7)} | |
| 67 | 69 | </a> | |
| 68 | 70 | <time class="commit-date" datetime={c.date}> | |
| 69 | - | {new Date(c.date).toLocaleString()} | |
| 71 | + | {formatDateTime(c.date)} | |
| 70 | 72 | </time> | |
| 71 | 73 | </div> | |
| 72 | 74 | </li> | |
Msrc/views/repos/RepoList.tsx
| @@ -1,4 +1,5 @@ | |||
|---|---|---|---|
| 1 | 1 | import type { RepositoryRow } from "../../db/index.ts"; | |
| 2 | + | import { formatDate } from "../../lib/formatDate.ts"; | |
| 2 | 3 | import type { SessionUser } from "../../middleware/session.ts"; | |
| 3 | 4 | import { Layout } from "../layout.tsx"; | |
| 4 | 5 | import { Pagination, type PaginationInfo } from "../Pagination.tsx"; | |
| @@ -76,9 +77,7 @@ export function RepoList({ user, repos, search, pagination }: RepoListProps) { | |||
|---|---|---|---|
| 76 | 77 | class="repo-date" | |
| 77 | 78 | datetime={repo.created_at} | |
| 78 | 79 | > | |
| 79 | - | {new Date( | |
| 80 | - | repo.created_at, | |
| 81 | - | ).toLocaleDateString()} | |
| 80 | + | {formatDate(repo.created_at)} | |
| 82 | 81 | </time> | |
| 83 | 82 | </div> | |
| 84 | 83 | </li> | |