من الثواني إلى السنوات: حساب الوقت النسبي في C# بشكل صحيح

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا نحتاج "الوقت النسبي"؟

\n\n

هل تساءلت يومًا لماذا تكتب مواقع التواصل الاجتماعي والأخبار "منذ ساعتين" أو "أمس"، بدلاً من "25.04.2025 14:32"؟ لأن دماغنا يدرك الوقت النسبي بشكل أسرع بكثير. التاريخ المطلق يتطلب تحليلاً: "حسنًا، اليوم هو 25، إذن كان هذا...". التاريخ النسبي يعطي الإجابة فورًا.

\n\n

إذا كنت تكتب بلغة C# - سواء كان تطبيق ويب ASP.NET، أو تطبيق سطح مكتب، أو بوت Telegram - فستحتاج عاجلاً أم آجلاً إلى عرض الوقت للمستخدم بصيغة "للتو"، "منذ 3 دقائق" أو "منذ حوالي عام". على Stack Overflow، حصد سؤال "Calculate relative time in C#" آلاف المشاهدات، مما يعني أنه ألم حقيقي للمطورين.

\n\n

في هذه المقالة، سنشرح الطريقة الأكثر صحة ومرونة لحساب الوقت النسبي في C#. ستحصل على كود جاهز يمكنك إدراجه مباشرة في مشروعك، وستفهم كيف يعمل، وستعرف كيفية تخصيصه لأي احتياجات.

\n\n

المشكلة: ما الخطأ في طرح التواريخ البسيط؟

\n\n

أول ما يتبادر إلى الذهن هو طرح تاريخ من آخر والحصول على TimeSpan. نعم، هذا يعمل. لكن الشيطان يكمن في التفاصيل:

\n\n
    \n
  • القيم الحدية. متى تنتهي "الدقيقة" وتبدأ "الساعة"؟ ومتى تتحول "الساعة" إلى "يوم"؟
  • \n
  • التواريخ المستقبلية. ماذا لو كان التاريخ في المستقبل؟ هل نعرض "بعد 5 دقائق" أم "بعد يوم واحد"؟
  • \n
  • قابلية قراءة الكود. إذا قمت بتوزيع المنطق في جميع أنحاء المشروع، فستصاب بالارتباك بعد شهر.
  • \n
\n\n

لذلك، نحتاج ليس فقط إلى قطعة كود، بل إلى طريقة واحدة قابلة لإعادة الاستخدام.

\n\n

الحل: طريقة عالمية لحساب الوقت النسبي

\n\n

أفضل طريقة هي كتابة دالة ثابتة واحدة تأخذ DateTime (أو DateTimeOffset) وتعيد سلسلة نصية جميلة. إليك تطبيق أساسي ولكنه قوي جدًا يمكن العثور عليه في مناقشات Stack Overflow وتكييفه:

\n\n
using System;\n\npublic static class TimeHelper\n{\n    public static string GetRelativeTime(DateTime dateTime)\n    {\n        var now = DateTime.Now;\n        var utcNow = DateTime.UtcNow;\n\n        // مهم: المقارنة في نفس المنطقة الزمنية!\n        var timeSpan = now - dateTime;\n\n        // الحالة 1: التاريخ في المستقبل\n        if (timeSpan.TotalSeconds < 0)\n        {\n            // حساب القيمة المطلقة للمستقبل\n            timeSpan = timeSpan.Duration();\n            if (timeSpan.TotalMinutes < 1)\n                return "بعد بضع ثوان";\n            if (timeSpan.TotalMinutes < 60)\n                return $"بعد {timeSpan.Minutes} دقيقة.";\n            if (timeSpan.TotalHours < 24)\n                return $"بعد {timeSpan.Hours} ساعة.";\n            if (timeSpan.TotalDays < 30)\n                return $"بعد {timeSpan.Days} يوم.";\n            if (timeSpan.TotalDays < 365)\n                return $"بعد {timeSpan.Days / 30} شهر.";\n            return $"بعد {timeSpan.Days / 365} سنة.";\n        }\n\n        // الحالة 2: الماضي\n        if (timeSpan.TotalMinutes < 1)\n            return "للتو";\n        if (timeSpan.TotalMinutes < 60)\n            return $"منذ {timeSpan.Minutes} دقيقة.";\n        if (timeSpan.TotalHours < 24)\n            return $"منذ {timeSpan.Hours} ساعة.";\n        if (timeSpan.TotalDays < 7)\n            return $"منذ {timeSpan.Days} يوم.";\n\n        // للتواريخ الأقدم من أسبوع نستخدم الأيام\n        if (timeSpan.TotalDays < 30)\n            return $"منذ {(int)timeSpan.TotalDays} يوم.";\n        if (timeSpan.TotalDays < 365)\n        {\n            int months = (int)(timeSpan.TotalDays / 30);\n            return $"منذ {months} شهر.";\n        }\n\n        int years = (int)(timeSpan.TotalDays / 365);\n        return $"منذ {years} سنة.";                

المدونات

توصيات الكتب