diff --git a/frontend/src/components/MatchList.tsx b/frontend/src/components/MatchList.tsx
index f55a90b..1e86f14 100644
--- a/frontend/src/components/MatchList.tsx
+++ b/frontend/src/components/MatchList.tsx
@@ -1,6 +1,6 @@
import { useNavigate } from "react-router-dom";
-import { formatDuration } from "../domain/format";
+import { formatDate, formatDuration } from "../domain/format";
import { winReasonLabel } from "../domain/winReasons";
import type { MatchListItem } from "../domain/types";
import { PlayerLink } from "./PlayerLink";
@@ -24,7 +24,7 @@ export function MatchListView({ items }: { items: MatchListItem[] }) {
onClick={() => navigate(`/match/${m.id}`)}
>
- {m.played_at}
+ {formatDate(m.played_at)}
{inProgress ? (
идёт
) : (
diff --git a/frontend/src/domain/format.ts b/frontend/src/domain/format.ts
index a9f93b8..8a4b6cd 100644
--- a/frontend/src/domain/format.ts
+++ b/frontend/src/domain/format.ts
@@ -28,6 +28,14 @@ export function formatTime(iso: string | null | undefined): string {
}
}
+// «Дата игры» приходит date-only строкой (YYYY-MM-DD) — просто переставляем части,
+// без сдвига пояса (бэкенд уже посчитал дату в поясе приложения).
+export function formatDate(iso: string | null | undefined): string {
+ if (!iso) return "—";
+ const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
+ return m ? `${m[3]}.${m[2]}.${m[1]}` : iso;
+}
+
export function formatDateTime(iso: string | null | undefined): string {
if (!iso) return "—";
try {
diff --git a/frontend/src/pages/GroupPage.tsx b/frontend/src/pages/GroupPage.tsx
index bb01393..8ef89ad 100644
--- a/frontend/src/pages/GroupPage.tsx
+++ b/frontend/src/pages/GroupPage.tsx
@@ -6,6 +6,7 @@ import { GroupSwitcher } from "../components/GroupSwitcher";
import { Leaderboard } from "../components/Leaderboard";
import { MatchListView } from "../components/MatchList";
import { Spinner } from "../components/Spinner";
+import { formatDate } from "../domain/format";
import { useMe } from "../hooks/auth";
import { useGroup, useGroupMatches, useGroupStats } from "../hooks/groups";
@@ -49,7 +50,7 @@ export function GroupPage() {
Партий: {stats?.total_matches ?? 0}
- {stats?.last_match_at ? ` · последняя: ${stats.last_match_at}` : ""}
+ {stats?.last_match_at ? ` · последняя: ${formatDate(stats.last_match_at)}` : ""}
diff --git a/frontend/src/pages/MatchDetailPage.tsx b/frontend/src/pages/MatchDetailPage.tsx
index 6e13008..d8ebc67 100644
--- a/frontend/src/pages/MatchDetailPage.tsx
+++ b/frontend/src/pages/MatchDetailPage.tsx
@@ -6,7 +6,7 @@ import { ConfirmDialog } from "../components/ConfirmDialog";
import { MatchMedia } from "../components/MatchMedia";
import { PlayerLink } from "../components/PlayerLink";
import { Spinner } from "../components/Spinner";
-import { formatDuration, formatTime } from "../domain/format";
+import { formatDate, formatDuration, formatTime } from "../domain/format";
import { WIN_REASONS, type WinReason, winReasonLabel } from "../domain/winReasons";
import { useToast } from "../context/ToastContext";
import {
@@ -120,7 +120,7 @@ export function MatchDetailPage() {
-
{match.played_at}
+
{formatDate(match.played_at)}
{inProgress ? (
идёт
) : (
diff --git a/frontend/src/pages/admin/AdminRecordsPage.tsx b/frontend/src/pages/admin/AdminRecordsPage.tsx
index 8bbab19..e4de2f4 100644
--- a/frontend/src/pages/admin/AdminRecordsPage.tsx
+++ b/frontend/src/pages/admin/AdminRecordsPage.tsx
@@ -3,6 +3,7 @@ import { useMemo, useState } from "react";
import { ApiError } from "../../api/client";
import { ConfirmDialog } from "../../components/ConfirmDialog";
+import { formatDate } from "../../domain/format";
import { Spinner } from "../../components/Spinner";
import { Switch } from "../../components/Switch";
import { useToast } from "../../context/ToastContext";
@@ -54,7 +55,7 @@ export function AdminRecordsPage() {
-
#{m.id} · {m.played_at}
+
#{m.id} · {formatDate(m.played_at)}
{!grouped &&
· {m.group_name}}
{m.player_count} игр. · автор {m.created_by}