diff --git a/apps/frontend/app/channels/[id]/page.tsx b/apps/frontend/app/channels/[id]/page.tsx index e533415..66207df 100644 --- a/apps/frontend/app/channels/[id]/page.tsx +++ b/apps/frontend/app/channels/[id]/page.tsx @@ -2,6 +2,7 @@ import { notFound } from "next/navigation"; import Link from "next/link"; import { prisma } from "@streamclipper/db"; import { fetchChannelStatuses } from "../../../lib/apiDaemon"; +import { formatTr } from "../../../lib/formatDate"; import { deleteRawSegment, deleteCandidateSegment, @@ -113,7 +114,7 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{

Aktif: {channel.isActive ? "evet" : "hayır"} · Son kontrol:{" "} - {channel.lastCheckedAt ? new Date(channel.lastCheckedAt).toLocaleString("tr-TR") : "—"} + {channel.lastCheckedAt ? formatTr(channel.lastCheckedAt) : "—"}

- {new Date(status.lastPollError.at).toLocaleString("tr-TR")} + {formatTr(status.lastPollError.at)}
@@ -199,8 +200,8 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{
               
                 
                   
-                    {new Date(session.startedAt).toLocaleString("tr-TR")}
-                    {session.endedAt ? ` – ${new Date(session.endedAt).toLocaleString("tr-TR")}` : " (devam ediyor)"}
+                    {formatTr(session.startedAt)}
+                    {session.endedAt ? ` – ${formatTr(session.endedAt)}` : " (devam ediyor)"}
                   
                   {session.totalSegments} segment
                 
diff --git a/apps/frontend/app/page.tsx b/apps/frontend/app/page.tsx
index cb0e1a9..9c99550 100644
--- a/apps/frontend/app/page.tsx
+++ b/apps/frontend/app/page.tsx
@@ -2,6 +2,7 @@ import Link from "next/link";
 import { prisma } from "@streamclipper/db";
 import { addChannel, toggleChannelActive, toggleAllChannels, checkChannelNow } from "./actions";
 import { fetchChannelStatuses } from "../lib/apiDaemon";
+import { formatTr } from "../lib/formatDate";
 import { Button } from "@/components/ui/button";
 import { Input } from "@/components/ui/input";
 import { Badge } from "@/components/ui/badge";
@@ -94,7 +95,7 @@ export default async function DashboardPage() {
                           {status?.lastPollError && (
                             
                               hata
                             
@@ -102,7 +103,7 @@ export default async function DashboardPage() {
                         
                       
                       
-                        {c.lastCheckedAt ? new Date(c.lastCheckedAt).toLocaleString("tr-TR") : "—"}
+                        {c.lastCheckedAt ? formatTr(c.lastCheckedAt) : "—"}
                       
                       
                         
diff --git a/apps/frontend/app/segments/page.tsx b/apps/frontend/app/segments/page.tsx index f45c722..3fa4b62 100644 --- a/apps/frontend/app/segments/page.tsx +++ b/apps/frontend/app/segments/page.tsx @@ -1,5 +1,6 @@ import { prisma } from "@streamclipper/db"; import { deleteRawSegment, deleteCandidateSegment, retryRender, cancelRender } from "../actions"; +import { formatTr } from "../../lib/formatDate"; import { ConfirmButton } from "../components/ConfirmButton"; import { Button } from "@/components/ui/button"; import { Badge, type badgeVariants } from "@/components/ui/badge"; @@ -46,7 +47,7 @@ export default async function SegmentsPage() {
{segment.filePath}

- {segment.duration}sn · {new Date(segment.startedAt).toLocaleString("tr-TR")} + {segment.duration}sn · {formatTr(segment.startedAt)}

{segment.status} diff --git a/apps/frontend/app/settings/page.tsx b/apps/frontend/app/settings/page.tsx index 1004675..c027de4 100644 --- a/apps/frontend/app/settings/page.tsx +++ b/apps/frontend/app/settings/page.tsx @@ -1,5 +1,6 @@ import { prisma } from "@streamclipper/db"; import { updateYtdlpCookies, updateSystemSettings, updateNotificationPrefs, updateSttEnabled } from "../actions"; +import { formatTr } from "../../lib/formatDate"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -38,7 +39,7 @@ export default async function SettingsPage() { YouTube Cookie'leri - {setting ? `son güncelleme: ${setting.updatedAt.toLocaleString("tr-TR")}` : "hiç ayarlanmadı"} + {setting ? `son güncelleme: ${formatTr(setting.updatedAt)}` : "hiç ayarlanmadı"} diff --git a/apps/frontend/app/users/page.tsx b/apps/frontend/app/users/page.tsx index b70a337..7063789 100644 --- a/apps/frontend/app/users/page.tsx +++ b/apps/frontend/app/users/page.tsx @@ -1,6 +1,7 @@ import { prisma } from "@streamclipper/db"; import { getSession } from "../../lib/auth"; import { addUser, deleteUser } from "./actions"; +import { formatTr } from "../../lib/formatDate"; import { ConfirmButton } from "../components/ConfirmButton"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -56,7 +57,7 @@ export default async function UsersPage() { )} - {u.createdAt.toLocaleString("tr-TR")} + {formatTr(u.createdAt)} {u.id !== session?.sub && users.length > 1 && ( diff --git a/apps/frontend/lib/formatDate.ts b/apps/frontend/lib/formatDate.ts new file mode 100644 index 0000000..c16fffb --- /dev/null +++ b/apps/frontend/lib/formatDate.ts @@ -0,0 +1,10 @@ +/** + * Server (Coolify/Hetzner) runs in UTC, but the panel is used from Turkey + * (UTC+3, no DST since 2016) — `.toLocaleString("tr-TR")` alone formats + * with tr-TR conventions but still uses the *server's* timezone for the + * actual time value, which was showing everything 3h behind. Always pin + * the timezone explicitly instead of relying on the runtime's default. + */ +export function formatTr(date: Date | string): string { + return new Date(date).toLocaleString("tr-TR", { timeZone: "Europe/Istanbul" }); +}