كيفية التعامل مع المناطق الزمنية في Next.js (Pages Router) v16

عرض الأوقات بالمنطقة الزمنية المحلية للمستخدم

المشكلة

عندما تعرض التطبيقات الأوقات دون مراعاة موقع المستخدم، ينشأ الارتباك. الاجتماع المجدول في "3:00 مساءً" يعني لحظات مختلفة اعتماداً على ما إذا كان المشاهد في نيويورك أو لندن أو طوكيو. إذا قام الخادم بعرض وقت بتوقيت UTC أو منطقته الزمنية الخاصة، يرى المستخدمون في المناطق الأخرى أوقاتاً محلية غير صحيحة، مما يؤدي إلى تفويت المواعيد وأخطاء الجدولة. يجب تفسير نفس الطابع الزمني بشكل مختلف لكل مستخدم بناءً على منطقته الزمنية.

الحل

قم بتخزين الطوابع الزمنية بتنسيق عالمي مثل ISO 8601 أو الطوابع الزمنية Unix، ثم قم بتنسيقها للعرض في المنطقة الزمنية المحلية للمستخدم على جانب العميل. اكتشف المنطقة الزمنية للمستخدم باستخدام واجهة برمجة التطبيقات الدولية للمتصفح ومررها إلى دوال التنسيق في react-intl. يضمن هذا أن كل مستخدم يرى الأوقات معدلة وفقاً لمنطقته الزمنية الخاصة، مما يزيل الغموض حول موعد حدوث الأحداث.

الخطوات

1. اكتشاف المنطقة الزمنية للمستخدم على جانب العميل

تُرجع Intl.DateTimeFormat().resolvedOptions().timeZone في المتصفح معرف المنطقة الزمنية IANA للمستخدم، مثل America/New_York أو Europe/London. أنشئ hook مخصص للوصول إلى هذه القيمة.

import { useState, useEffect } from "react";

export function useUserTimeZone() {
  const [timeZone, setTimeZone] = useState<string>("UTC");

  useEffect(() => {
    const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;
    setTimeZone(detected);
  }, []);

  return timeZone;
}

يعمل هذا الـ hook فقط على جانب العميل، مما يتجنب عدم تطابق الترطيب، ويستخدم UTC افتراضياً حتى يتم اكتشاف المنطقة الزمنية.

2. تنسيق التواريخ بالمنطقة الزمنية للمستخدم باستخدام FormattedDate

مرر خيار timeZone إلى طرق التنسيق في react-intl للتحكم في المنطقة الزمنية المستخدمة للعرض. استخدم مكون <FormattedDate> مع المنطقة الزمنية المكتشفة.

import { FormattedDate } from "react-intl";
import { useUserTimeZone } from "../hooks/useUserTimeZone";

interface EventDateProps {
  timestamp: string;
}

export function EventDate({ timestamp }: EventDateProps) {
  const userTimeZone = useUserTimeZone();

  return (
    <FormattedDate
      value={new Date(timestamp)}
      timeZone={userTimeZone}
      year="numeric"
      month="long"
      day="numeric"
      hour="numeric"
      minute="2-digit"
      timeZoneName="short"
    />
  );
}

تضمن الخاصية timeZone تنسيق التاريخ بالمنطقة الزمنية المحلية للمستخدم بدلاً من المنطقة الزمنية للخادم أو UTC.

3. تنسيق الأوقات بشكل إجرائي باستخدام useIntl

في السيناريوهات التي تحتاج فيها إلى سلسلة نصية منسقة بدلاً من مكون، استخدم خطاف useIntl للوصول إلى واجهة برمجة التطبيقات الإجرائية للتنسيق.

import { useIntl } from "react-intl";
import { useUserTimeZone } from "../hooks/useUserTimeZone";

interface MeetingTimeProps {
  startTime: string;
}

export function MeetingTime({ startTime }: MeetingTimeProps) {
  const intl = useIntl();
  const userTimeZone = useUserTimeZone();

  const formattedTime = intl.formatDate(new Date(startTime), {
    timeZone: userTimeZone,
    hour: "numeric",
    minute: "2-digit",
    timeZoneName: "short",
  });

  return <span title={startTime}>{formattedTime}</span>;
}

تقبل الدالة formatDate معاملاً ثانياً مع DateTimeFormatOptions، بما في ذلك timeZone، مما يتيح التحكم الكامل في كيفية عرض الطابع الزمني.

4. تمرير الطوابع الزمنية للخادم كسلاسل نصية ISO

في getServerSideProps، قم بجلب البيانات في وقت الطلب وتمريرها إلى مكون الصفحة كخصائص. قم بتسلسل التواريخ كسلاسل نصية ISO 8601 للحفاظ على معلومات المنطقة الزمنية.

import { GetServerSideProps } from "next";

interface Event {
  id: string;
  title: string;
  startTime: string;
}

interface EventPageProps {
  event: Event;
}

export const getServerSideProps: GetServerSideProps<
  EventPageProps
> = async () => {
  const event = {
    id: "1",
    title: "Team Meeting",
    startTime: new Date("2025-02-15T15:00:00Z").toISOString(),
  };

  return {
    props: { event },
  };
};

export default function EventPage({ event }: EventPageProps) {
  return (
    <div>
      <h1>{event.title}</h1>
      <EventDate timestamp={event.startTime} />
    </div>
  );
}

تحافظ سلاسل ISO النصية على اللحظة الدقيقة في الوقت، مما يسمح للتنسيق من جانب العميل بتحويلها بدقة إلى أي منطقة زمنية.