كيفية استخدام NetworkDays في VBA (مع مثال)

دليل أكاديمي شامل يوضح كيفية استخدام دالة NetworkDays في برمجة VBA لحساب أيام العمل الصافية بدقة، مدعوماً بشروحات برمجية وأمثلة تطبيقية متقدمة.

Mohammed looti أكاديمي وباحث متخصص في علم النفس
تاريخ النشر
تمت المراجعة العلمية · د. مروة عبد العظيم · 23 أكتوبر، 2026
مراجعة وتدقيق علمي معتمد تاريخ التدقيق: 23 أكتوبر، 2026
د. مروة عبد العظيم دكتوراه في علم النفس
عضو هيئة التدريس • جامعة كربلاء
معايير التدقيق والاعتماد السريري

يخضع هذا المحتوى لمعايير ضبط الجودة والتدقيق العلمي والأكاديمي الصارمة في شبكة علم النفس العربي، لضمان صحة المعلومات ودقتها السريرية ومطابقتها لأحدث الأدلة والبراهين الصادرة عن الجمعيات النفسية والطبية المعتمدة (APA / WHO).

تعد النمذجة الزمنية الدقيقة وإدارة الجداول التشغيلية من الركائز الأساسية التي تعتمد عليها المؤسسات الحديثة في تقييم الإنتاجية، وإدارة سلاسل الإمداد، وتحديد مسارات المشاريع الحرجة بدقة بالغة. وفي بيئات الأعمال التي تتعامل مع آلاف المعاملات اليومية، تبرز الحاجة الملحة إلى أدوات برمجية متطورة قادرة على التمييز بين الأيام التقويمية المطلقة وأيام العمل الفعلية. إن احتساب الفترات الزمنية بمجرد طرح التواريخ يؤدي إلى تشوهات تحليلية فادحة، نظراً لتجاهله العطلات الأسبوعية الثابتة والإجازات الرسمية المتغيرة، مما ينعكس سلباً على تقديرات تكلفة العمل ومعدلات الإنجاز ومؤشرات الأداء الرئيسية (KPIs).

يمثل تطبيق Microsoft Excel أحد أكثر الحلول انتشاراً في معالجة هذه البيانات، وتعد دالة NetworkDays الأداة الرياضية القياسية المدمجة لحساب أيام العمل الصافية. ومع ذلك، فإن الانتقال من الاستخدام اليدوي التفاعلي لصيغ الجداول الحسابية إلى الأتمتة الشاملة يقتضي استدعاء هذه الدالة برمجياً عبر بيئة Visual Basic for Applications (VBA). تتيح هذه البيئة تحويل العمليات الحسابية المتكررة إلى إجراءات مؤتمتة فائقة السرعة، مما يضمن معالجة البيانات الضخمة بدقة متناهية ودون الحاجة إلى التدخل البشري المستمر الذي تحفه مخاطر الأخطاء الإجرائية.

يهدف هذا المقال الأكاديمي الموسع إلى تقديم دليل هندسي شامل لكيفية توظيف واستدعاء دالة NetworkDays داخل بيئة VBA، مع استعراض الأبعاد الرياضية والمنطقية المنظمة لعملها. سنتناول البنية النحوية البرمجية للدالة، وآليات إدارة الذاكرة، والتعامل مع استثناءات العطلات الرسمية، وتحليل الأخطاء البرمجية الشائعة وطرق احتوائها، فضلاً عن تقديم أمثلة تطبيقية مدعومة بنماذج شفرات برمجية قابلة لإعادة الاستخدام، مما يمنح المطورين والمحللين الماليين والتقنيين فهماً عميقاً لتحسين كفاءة تطبيقاتهم المؤسسية.

1. مقدمة نظرية حول دالة NetworkDays وأهميتها البرمجية في VBA

1.1 المفهوم الرياضي والمنطقي لاحتساب أيام العمل الصافية

يقوم المفهوم الرياضي لاحتساب أيام العمل الصافية (Net Working Days) على تجريد الفاصل الزمني الكلي المحصور بين نقطتين زمنيتين محددتين ($T_1$ و $T_2$) من كافة الانقطاعات الزمنية غير الإنتاجية. تقليدياً، تُعرّف الفترة التقويمية بالمعادلة البسيطة $\Delta T = T_2 – T_1 + 1$، حيث يتم احتساب اليوم الأول واليوم الأخير ضمن المدى الزمني. غير أن هذه المعادلة تفترض استمرارية النشاط البشري والمؤسسي على مدار الساعة وطوال أيام الأسبوع، وهو افتراض يتناقض جذرياً مع الواقع التشغيلي والتشريعي للشركات والمؤسسات حول العالم.

تعتمد النمذجة الرياضية لدالة NetworkDays على خوارزمية فحص تقويمي تقوم بتصنيف كل يوم في المدى $[T_{start}, T_{\end}]$ إلى إحدى فئتين رئيسيتين: يوم عمل (Business Day) أو يوم راحة (Non-working Day). تُستبعد أيام عطلة نهاية الأسبوع تلقائياً، والتي تعتمد في الدالة الكلاسيكية على يومي السبت والأحد كقيمة افتراضية غير قابلة للتعديل المباشر في هذا الإجراء. كما تطبق الدالة مصفوفة استبعاد إضافية للعطلات الرسمية المحددة، مع مراعاة منطقية بالغة الأهمية؛ حيث يُمنع الحساب المزدوج لليوم إذا تزامنت عطلة رسمية مع عطلة نهاية أسبوع قياسية، مما يحفظ الدقة التوزيعية والعددية للفترة الزمنية الإجمالية.

تتجلى أهمية هذه النمذجة الدقيقة في إدارة المشاريع الهندسية، حيث يُقاس مؤشر التباين الزمني (Schedule Variance) ومدى التوافق مع المسار الحرج (Critical Path Method) بناءً على أيام العمل الفعلية التي تتوفر فيها القوة العاملة وموارد البناء. إن حدوث انحراف بسيط في حساب أيام العمل الصافية يمتد ليؤثر على معادلات كفاءة التكلفة وتقدير ساعات العمل المعيارية، ما قد يقود الإدارة العليا إلى اتخاذ قرارات تخطيطية غير مدروسة ناجمة عن بيانات مشوهة.

1.2 دور كائن WorksheetFunction في استدعاء دوال إكسل عبر بيئة VBA

تتميز لغة Visual Basic for Applications ببيئة عمل خاصة ومكتبة دوال مدمجة (VBA Native Functions)، إلا أن هذه المكتبة تفتقر إلى بعض الدوال الإحصائية والمالية والتقويمية المعقدة المتاحة في واجهة ورقة العمل التقليدية. لحل هذه الإشكالية البنيوية، توفر مايكروسوفت كائن الربط المرجعي WorksheetFunction، والذي يمثل جسراً برمجياً يتيح للمطورين استدعاء معظم دوال ورقة العمل الحسابية وتنفيذها داخل الأكواد البرمجية مباشرة.

تاريخياً، لم تكن دالة NetworkDays مدمجة في المحرك الأساسي لحزم أوفيس القديمة، بل كانت تتطلب تفعيل الحزمة التحليلية الإضافية (Analysis ToolPak) ومكتبتها البرمجية atpvbaen.xls قبل إصدار إكسل 2007. ومع إعادة هيكلة المحرك الحسابي في الإصدارات الحديثة، أصبحت الدالة جزءاً متأصلاً في الكائن WorksheetFunction، مما أتاح استدعاءها عبر الصياغة المعيارية Application.WorksheetFunction.NetworkDays بأعلى درجات الاستقرار والموثوقية التقنية.

من الناحية المعمارية، يتضمن استدعاء دالة ورقة العمل عبر كائن WorksheetFunction إرسال نداء عبر واجهة برمجية بينية (COM Interop)، حيث يتم ترحيل الوسائط من بيئة محرك VBA إلى محرك الحساب الرياضي الخاص بإكسل، ثم استقبال الناتج وإسناده إلى المتغير المستهدف. هذا المسار البرمجي يتميز بكفاءة حسابية استثنائية مقارنة بإعادة كتابة خوارزميات حساب التقاويم يدوياً بواسطة حلقات Loop في VBA، نظراً لأن المحرك الحسابي الأساسي لإكسل مكتوب بلغة C++ عالية الأداء ومُحسّن للتعامل مع العمليات المادية للتقاويم الزمنية وإدارة الذاكرة المؤقتة بكفاءة قصوى.

1.3 الفروق الجوهرية بين المعالجة اليدوية والأتمتة البرمجية

تحفل المعالجة اليدوية لحسابات الأيام الصافية عبر كتابة الصيغ الحسابية مباشرة في خلايا ورقة العمل بمخاطر تشغيلية واسعة النطاق، لا سيما في المشروعات المؤسسية الضخمة. تكمن المشكلة الأولى في هشاشة الصيغ اليدوية؛ إذ يمكن للمستخدم النهائي تعديل الصيغة بطريق الخطأ أو كسر مراجع النطاقات الجغرافية والزمنية، مما ينشئ أخطاء صامتة (Silent Errors) قد لا تُكتشف إلا بعد استخراج التقارير وتوزيعها على صناع القرار.

في المقابل، توفر الأتمتة البرمجية عبر VBA بيئة معزولة ومنضبطة تخضع لمعايير الحوكمة والتحكم في الكود. يُحفظ المنطق الحسابي داخل وحدة نمطية (Standard Module) محمية بكلمة مرور إذا لزم الأمر، مما يمنع التلاعب بالمعادلات. علاوة على ذلك، تتميز الأتمتة بقدرتها على التعامل مع مجموعات البيانات المتدفقة والمتضخمة؛ حيث يمكن لروتين برمجي واحد فحص عشرات الآلاف من السجلات الزمنية، وإدراج مخرجات الحساب الصافية في أجزاء من الثانية، وتوجيه البيانات إلى تقارير موحدة دون تحميل واجهة المستخدم الرسومية أعباء معالجة ثقيلة.

علاوة على ذلك، تمنح الأتمتة المبرمجين مرونة استثنائية في إجراء عمليات التحقق المسبق من صحة البيانات (Data Sanitization)، كفحص خلو التواريخ من التناقض الزمني واستبعاد النصوص المعيبة وتطبيق معايير استجابة مخصصة وفقاً لقواعد العمل المعقدة، وهو ما يستحيل تحقيقه بذات السلاسة عبر الصيغ المباشرة المقيدة بشروط ورقة العمل التقليدية.

2. البنية النحوية والتركيبية لدالة NetworkDays في كود VBA

2.1 الصياغة البرمجية العامة وتوصيف المعاملات الأساسية

تأخذ دالة NetworkDays عند استدعائها داخل بيئة التطوير في Visual Basic for Applications قالباً برمجياً محدداً يخضع لقواعد بناء الجمل البرمجية الخاصة بكائن التطبيق. تظهر الصياغة النحوية النموذجية للدالة على النحو الآتي:

Application.WorksheetFunction.NetworkDays(Arg1, Arg2, [Arg3])

يتطلب هذا الميثود وسيطين إجباريين ووسيطاً واحداً اختيارياً، ويتم تفصيلها برمجياً ورياضياً كالتالي:

  • تاريخ البداية (Arg1 – Start_Date): يمثل نقطة الانطلاق الزمنية للمجال المراد احتسابه. يشترط أن يكون هذا المعامل تاريخاً تقويمياً صالحاً أو رقماً تسلسلياً زمنياً صحيحاً يتعرف عليه محرك إكسل. من الناحية الرياضية، يعد هذا التاريخ شمولياً (Inclusive)؛ أي أنه إذا صادف يوم عمل فعلي (كالخميس مثلاً)، فإن الدالة تحتسبه كأول يوم عمل في الناتج الإجمالي ولا تتجاهله.
  • تاريخ النهاية (Arg2 – End_Date): يمثل نقطة الإغلاق التقويمي للمجال المحسوب. يخضع لنفس شروط صحة البيانات الخاصة بتاريخ البداية، ويُعامل أيضاً كمعامل شمولي يتم ضمه للحساب الفعلي إذا صادف أحد أيام العمل.

في سياق كتابة الكود، يمكن تمرير هذه المعاملات إما كمتغيرات صريحة من نوع Date تم إنشاؤها عبر التوابع الزمنية مثل DateSerial(YYYY, MM, DD)، أو من خلال تمرير كائنات النطاق Range التي تشير مباشرة إلى الخلايا المحتوية على تلك التواريخ، مثل Range("A2") و Range("B2"). تضمن هذه المرونة البرمجية توافق الدالة مع مختلف أساليب بناء النماذج داخل بيئة العمل.

2.2 معالجة وسيطة العطلات الرسمية (Holidays) كمعامل اختياري

تُمثل الوسيطة الثالثة [Arg3]، والمعروفة باسم Holidays، المعامل الديناميكي الذي يسمح للمطور بتخصيص خوارزمية الحساب لتلائم التقاويم التشريعية والوطنية للمؤسسة. تُعد هذه الوسيطة اختيارية برمجياً؛ ففي حال إغفال تمريرها، تكتفي الدالة باستبعاد أيام السبت والأحد فقط عبر المدى الزمني المحدد، معتبرة أن بقية الأيام هي فترات عمل تشغيلية كاملة.

عند الرغبة في إدراج العطلات الرسمية، يمكن تمثيل هذا المعامل بطرق متعددة داخل كود VBA:

  • تمرير كائن نطاق مستمر (Continuous Range Object) يشير إلى قائمة التواريخ المراد استبعادها داخل ورقة العمل، مثل: Range("E2:E10").
  • تمرير مصفوفة برمجية داخل الذاكرة (Memory Array) تحتوي على قيم تسلسلية من نوع Date أو Variant، تم بناؤها مسبقاً وتعبئتها بواسطة الكود دون الحاجة لوجود جدول وسيط في ورقة العمل.

تتمتع خوارزمية الدالة بآلية تحقق داخلي تضمن عدم التأثير المزدوج للعطلات؛ فإذا أدرج المبرمج تاريخ عطلة وطنية يصادف يوم سبت أو أحد، فإن الدالة تتجاهل هذا التاريخ ولا تطرحه مرتين من الإجمالي التراكمي للأيام. يضمن هذا السلوك الحسابي سلامة النتائج الإحصائية وتوافقها المطلق مع قوانين العمل القياسية.

2.3 القيود الحسابية وأنواع البيانات المتوافقة مع الدالة

يتطلب التعامل السليم مع دالة NetworkDays الانتباه الصارم لسلامة أنواع البيانات (Data Types) الممررة إليها لتجنب إطلاق أخطاء وقت التشغيل (Runtime Errors). تخزن بيئة إكسل التواريخ كأرقام تسلسلية ذات فاصلة عائمة مزدوجة الدقة (Double)، حيث يمثل الرقم الصحيح عدد الأيام المنقضية منذ الأول من يناير عام 1900، بينما يمثل الجزء العشري كسور اليوم والساعات.

تشمل المتطلبات والقيود الحسابية ما يلي:

  • التوافق النوعي: يجب أن ترسل المدخلات إلى الدالة كنوع بيانات Date أو Long أو Double. يُعد إرسال سلاسل نصية تمثل التواريخ (Strings) ممارسة برمجية خطرة، إذ تعتمد على الإعدادات الإقليمية للنظام (System Locale) مما يؤدي إلى ارتباك تفسير الأيام والشهور (على سبيل المثال، هل 04/05 يمثل الرابع من مايو أم الخامس من أبريل؟).
  • السلوك العكسي للتواريخ: إذا كان تاريخ البداية لاحقاً لتاريخ النهاية زمنياً ($T_{start} > T_{\end}$)، فإن الدالة لا تُلقي خطأ برمجياً يوقف التنفيذ، بل تعيد ناتجاً سالباً يمثل معكوس أيام العمل الصافية، وهو ما يتطلب معالجة برمجية شرطية لتفادي إفساد التقارير التجميعية.
  • التعامل مع القيم الفارغة: عند تمرير خلية فارغة إلى الدالة كمعامل تاريخ، يتعامل محرك إكسل مع القيمة الصفرية المكافئة لتاريخ 00/01/1900، مما ينتج عنه أرقام خيالية وغير منطقية قد تعطل التحليل المؤسسي الشامل.

3. تهيئة بيئة التطوير وورقة العمل لتنفيذ الكود التجريبي

3.1 هيكلة مصفوفة البيانات في ورقة عمل إكسل

قبل البدء في كتابة الشيفرة البرمجية، يتعين تأسيس بنية هيكلية معيارية للبيانات داخل ورقة العمل بهدف ضمان التوافق التام مع منطق الروتين البرمجي وتفادي إخفاقات الإسناد. يجب تخصيص ورقة عمل محددة (ولتكن باسم "ProjectSchedule" أو "Sheet1") مع تنظيم الأعمدة وفق النمط الهندسي التالي:

  • العمود A (تاريخ البدء – Start Date): يخصص هذا العمود لحفظ نقطة البداية الزمنية لكل مشروع أو مهمة. يجب تطبيق تنسيق زمني موحد على خلايا هذا النطاق، ويفضل التنسيق الدولي القياسي المعترف به عالمياً ومؤسسياً YYYY-MM-DD، لتلافي أي لبس في قراءة الشهور والأيام عبر الحواسيب المختلفة.
  • العمود B (تاريخ الانتهاء – End Date): يخصص لتسجيل التواريخ الختامية للمهام قيد الدراسة، مع تطبيق ذات التنسيق المعتمد في العمود A لضمان التماثل البصري والرقمي.
  • العمود C (أيام العمل الصافية – Net Working Days): يُترك هذا العمود فارغاً تماماً في بداية الأمر، حيث سيستخدمه الماكرو كمستودع نهائي لاستقبال المخرجات الرقمية المحسوبة برمجياً، ويُفضل ضبط تنسيقه كنطاق أرقام عامة أو صحيحة (General or Integer).

يوفر التحديد الدقيق للنطاقات من الخلية A2 وحتى الخلية B9 في السيناريو التجريبي بيئة مستقرة لاختبار الكود على عدد محدد من الحالات التي تجمع بين البدايات المتنوعة والنهايات المتداخلة وعطلات نهاية الأسبوع، مما يعطي مؤشراً دقيقاً على كفاءة الخوارزمية قبل تعميمها على نطاقات ديناميكية ضخمة.

3.2 الوصول إلى محرر Visual Basic for Applications وتجهيز الوحدة النمطية

للوصول إلى بيئة التطوير المتكاملة الخاصة بأتمتة التطبيقات، نتبع الإجراءات المعيارية التالية:

  1. فتح مصنف العمل المستهدف، والضغط على المفتاحين Alt + F11 عبر لوحة المفاتيح لاستدعاء نافذة محرر الأكواد (Visual Basic Editor – VBE).
  2. من القائمة العلوية للمحرر، اختيار الأمر Insert ثم النقر على Module. يؤدي هذا الإجراء إلى إنشاء وحدة نمطية قياسية فارغة (تسمى افتراضياً Module1)، وهي الحاوية المستقلة المناسبة لكتابة الإجراءات والوظائف العامة القابلة للاستدعاء عبر مختلف أرجاء المصنف.
  3. يجب التأكد من ظهور العبارة التصريحية Option Explicit في السطر الأول تماماً من الوحدة النمطية قبل كتابة أي كود برمجي. إذا لم تكن موجودة، يجب كتابتها يدوياً أو تفعيلها تلقائياً عبر الذهاب إلى Tools -> Options وتفعيل خيار Require Variable Declaration.

تفرض التعليمة Option Explicit نمطاً صارماً للبرمجة؛ إذ تمنع استخدام أي متغير داخل الكود دون الإعلان الصريح عنه وعن نوع بياناته التخزينية. يحمي هذا الإجراء المطور من أخطاء الكتابة الإملائية لأسماء المتغيرات (Typographical Errors)، والتي تعد من أخطر الأسباب المسببة للأخطاء المنطقية الخفية في لغة VBA.

3.3 معايير السلامة والتوثيق الأكاديمي للبيانات المدخلة

تتطلب كتابة البرمجيات الأكاديمية والمهنية تطبيق تدابير احترازية استباقية لضمان سلامة البيانات وحماية الملف من التلف البرمجي. الخطوة المحورية الأولى في هذا الإطار هي حفظ المصنف تحت امتداد يدعم وحدات الماكرو الحسابية؛ حيث يفقد المصنف العادي ذو الامتداد .XLSX كافة الشيفرات البرمجية بمجرد إغلاقه. بناءً على ذلك، يجب حفظ المصنف بصيغة Excel Macro-Enabled Workbook المرمزة بالامتداد .XLSM أو بصيغة الملفات الثنائية .XLSB الموصى بها في المشاريع الضخمة لتحسين سرعة الفتح والقراءة.

يتعين أيضاً توثيق البيانات المدخلة في النطاق A2:B9، والتأكد من خلوها من القيم الشاذة، مثل التواريخ الافتراضية الصفرية أو الفواصل غير المتوافقة التي قد يعتبرها النظام نصوصاً معزولة. كما يُشترط إدراج كتل التعليقات الوثائقية (Documentation Comments) داخل الوحدة النمطية باستخدام الفاصلة العليا (')، موضحاً فيها اسم المطور، وتاريخ التطوير، والهدف الأساسي من الروتين، والمعاملات المدخلة، والقيم المتوقع استخراجها، لضمان سهولة صيانة الكود وتطويره مستقبلاً.

4. التحليل التفصيلي للمثال التطبيقي الأساسي لحساب أيام العمل

4.1 تفكيك الشيفرة البرمجية لروتين CalculateNetworkDays

يوضح المثال البرمجي التالي الإجراء الأساسي المخصص لحساب أيام العمل الصافية لمجموعة من السجلات الزمنية المحددة في النطاق من السطر 2 وحتى السطر 9، مع كتابة النتائج مباشرة في العمود الموازي C:

Option Explicit

Public Sub CalculateNetworkDays()
    ' التصريح عن المتغيرات البرمجية الأساسية
    Dim i As Integer
    Dim ws As Worksheet
    
    ' إسناد ورقة العمل النشطة إلى متغير لتسهيل الإدارة المرجعية
    Set ws = ActiveSheet
    
    ' بدء الحلقة التكرارية للمرور على أسطر البيانات المحددة
    For i = 2 To 9
        ' استدعاء دالة ورقة العمل وإسناد النتيجة للخلية المقابلة
        ws.Range("C" & i).Value = Application.WorksheetFunction.NetworkDays( _
            ws.Range("A" & i).Value, _
            ws.Range("B" & i).Value _
        )
    Next i
    
    ' إرسال إشعار للمستخدم بإتمام المعالجة الحسابية بنجاح
    MsgBox "تم احتساب أيام العمل الصافية بنجاح لكافة السجلات.", vbInformation, "اكتمال المعالجة"
End Sub

يبدأ الكود بالإعلان الصريح عن الإجراء العام Sub CalculateNetworkDays()، مما يعني أن هذا الروتين متاح للتنفيذ من نافذة الماكرو الرئيسية في إكسل أو عبر ربطه بزر تفاعلي داخل واجهة المستخدم. تم التصريح عن متغير العداد i من نوع Integer، وهو نوع عددي ملائم تماماً للنطاقات الصغيرة المحدودة بأسطر معدودة لا تتجاوز الحدود القصوى لهذا النوع (التي تبلغ 32,767 رقماً)، مع تفضيل استخدام Long دائماً في المشاريع المفتوحة لاستيعاب كامل سعة أسطر إكسل البالغة 1,048,576 سطراً.

يضمن استخدام كائن ورقة العمل ws حصر العمليات داخل الورقة النشطة بوضوح، مما يمنع حدوث أخطاء مرجعية في حال كان المستخدم ينشط نافذة أخرى أو مصنفاً مختلفاً في لحظة إطلاق الماكرو.

4.2 آلية عمل حلقة التكرار For…Next وتتبع المتغير i

تمثل حلقة For...Next الهيكل الرياضي الأساسي الذي يدير التدفق الحسابي في هذا المثال. يتم ضبط عداد الحلقة ليبدأ من القيمة العددية 2 (وهو السطر الذي تبتدئ عنده البيانات الفعلية متجاوزاً أسطر العناوين والترويسات) ويستمر حتى السطر رقم 9 بصورة خطية متزايدة تلقائياً بمقدار 1 مع كل دورة كاملة.

تتم إدارة الخلايا ديناميكياً داخل الحلقة عبر تقنية الربط النصي (String Concatenation) باستخدام العامل &. فعندما تكون قيمة i = 2، يدمج الكود الحرف “A” مع الرقم 2 ليصبح التعبير ws.Range("A2")، مُمثلاً الخلية الأولى من عمود تاريخ البدء، وبالمثل يُنتج ws.Range("B2") لتاريخ الانتهاء، و ws.Range("C2") للخلية المستهدفة لكتابة المخرج.

مع انتهاء المعالجة في السطر الحالي، تصل الشيفرة إلى أمر المتابعة Next i، الذي يقوم بزيادة قيمة i بمقدار خطوة واحدة، ثم يعيد تقييم الشرط الحدودي؛ فإذا كانت قيمة المتغير الجديد لا تزال ضمن النطاق الأصغر من أو يساوي 9، يستمر التنفيذ في الدورة اللاحقة، وإذا تجاوزت القيمة هذا الحد، تنكسر الحلقة البرمجية تلقائياً ويتحول مسار المعالجة إلى السطر البرمجي الموالي للحلقة دون استهلاك غير مبرر لموارد المعالجة الدقيقة.

4.3 تنفيذ الاستدعاء WorksheetFunction.NetworkDays وقراءة المخرجات

في قلب الحلقة التكرارية، يتم تنفيذ الأمر الحسابي الفعلي عبر السطر:

ws.Range("C" & i).Value = Application.WorksheetFunction.NetworkDays(ws.Range("A" & i).Value, ws.Range("B" & i).Value)

يمر هذا الأمر الحسابي بالمراحل الإجرائية التالية في كل دورة تكرار:

  1. استخلاص الخاصية .Value من الخلية المحددة في العمود A وإرسالها كوسيط أول (تاريخ البداية).
  2. استخلاص الخاصية .Value من الخلية المحددة في العمود B وإرسالها كوسيط ثانٍ (تاريخ النهاية).
  3. تمرير الوسيطين إلى محرك دالة NetworkDays المدمج عبر الكائن WorksheetFunction.
  4. يقوم المحرك الرياضي بفحص كامل النطاق الزمني وإسقاط كافة أيام السبت والأحد المحصورة بين التاريخين، مع التحقق من شمولية طرفي الفترة.
  5. يُعاد الناتج العددي الصحيح ويُكتب فوراً في الخاصية .Value للخلية المقابلة في العمود C.

إذا افترضنا أن الخلية A2 تحتوي على التاريخ 2024-01-01 (يوم الإثنين) والخلية B2 تحتوي على التاريخ 2024-01-05 (يوم الجمعة)، فإن الدالة ستحسب الأيام: الإثنين، الثلاثاء، الأربعاء، الخميس، الجمعة؛ لتعيد القيمة 5. أما إذا امتد التاريخ في الخلية B2 إلى 2024-01-07 (يوم الأحد)، فإن النتيجة تظل 5 دون زيادة، لأن يومي السبت والأحد يتم استبعادهما حتمياً بواسطة منطق الدالة الرياضي.

5. تطوير المثال البرمجي: إدراج قائمة العطلات الرسمية المخصصة

5.1 تأسيس جدول العطلات الرسمية وتحديده كمتغير مرجعي

لا تتوقف الاحتياجات الحسابية في بيئات الأعمال الواقعية عند استبعاد الإجازات الأسبوعية، بل تتطلب بالضرورة دمج تقويم العطلات الوطنية والدينية والمؤسسية لضمان عدم تحميل فترات التوقف الرسمية على كفاءة التنفيذ. لتحقيق هذا المطلب، نقوم بإنشاء جدول مستقل ومخصص للعطلات داخل ورقة العمل، ولتكن في النطاق E2:E5.

يحتوي هذا النطاق على التواريخ الدقيقة للعطلات الرسمية التي تصادف فترة تنفيذ المهام. وللتعامل مع هذا النطاق برمجياً بكفاءة وأناقة، يتم الإعلان عن متغير من نوع كائن النطاق (Range Object) في بيئة VBA، وتعيين هذا المتغير ليشير مباشرة إلى النطاق الجغرافي المحدد بواسطة الكلمة المفتاحية Set:

Dim holidayRange As Range
Set holidayRange = ws.Range("E2:E5")

يمتاز هذا الأسلوب بفصل البيانات الثابتة عن الكود؛ حيث يتيح لمديري المشاريع ومسؤولي الموارد البشرية تحديث قائمة العطلات الرسمية من خلال واجهة إكسل مباشرة دون الحاجة لتعديل الشفرة المصدرية المكتوبة بلغة VBA، مما يعزز استدامة النظام ومرونته التشغيلية عبر السنوات المالية المتتابعة.

5.2 تحديث الصياغة البرمجية لاحتواء المعامل الإضافي

عقب إعداد المتغير المرجعي لقائمة العطلات، نقوم بتحديث الروتين الحسابي السابق ليقوم بتمرير هذا النطاق كمعامل ثالث في استدعاء الدالة. تتضح الصيغة المتطورة للماكرو في الكود الشامل التالي:

Option Explicit

Public Sub CalculateNetworkDaysWithHolidays()
    Dim i As Long
    Dim ws As Worksheet
    Dim holidayRange As Range
    
    Set ws = ActiveSheet
    ' تحديد النطاق المحتوي على تواريخ الإجازات الرسمية
    Set holidayRange = ws.Range("E2:E5")
    
    ' تشغيل الحلقة لمعالجة كافة السجلات المدرجة
    For i = 2 To 9
        ' استدعاء الدالة متضمنة الوسيط الثالث المستبعد للعطلات
        ws.Range("C" & i).Value = Application.WorksheetFunction.NetworkDays( _
            ws.Range("A" & i).Value, _
            ws.Range("B" & i).Value, _
            holidayRange _
        )
    Next i
    
    MsgBox "تم تحديث الحسابات واستبعاد أيام العطل الرسمية بنجاح.", vbInformation, "اكتمال المعالجة المتقدمة"
End Sub

عند تنفيذ هذه الصياغة المحدثة، يقوم محرك دالة NetworkDays بمراجعة كل يوم تقويمي يقع ضمن النطاق بين تاريخ البدء والانتهاء؛ فإذا كان اليوم يقع ضمن أيام العمل النظامية (من الإثنين حتى الجمعة في النمط الافتراضي)، يقوم المحرك بفحص إضافي للتأكد مما إذا كان التاريخ مدرجاً ضمن النطاق holidayRange. فإذا وُجد ضمن القائمة، يتم إسقاطه من الحساب النهائي، مما يؤدي إلى خفض إجمالي أيام العمل الصافية بدقة وموثوقية متناهية.

5.3 الدراسة الإحصائية لأثر استبعاد العطلات على النماذج التشغيلية

يظهر التحليل الإحصائي المقارن بين المخرجات الناتجة عن تفعيل وسيطة العطلات وإهمالها تبايناً ملحوظاً ينعكس على المؤشرات المالية والتشغيلية للمؤسسات. ففي عينة تشغيلية افتراضية مدتها شهر واحد يتخلله يومان من العطلات الوطنية الرسمية، يؤدي إغفال المعامل الثالث إلى تضخيم الطاقة الإنتاجية المقدرة بنسبة تصل إلى 9.5% إلى 10% (بافتراض شهر عمل يحتوي على 21 أو 22 يوم عمل تقريبي).

هذا الانحراف الإحصائي، على الرغم من ظهوره كأرقام محدودة على مستوى الفرد الواحد، يتفاقم بصورة أسية عند تطبيقه على ميزانيات تشغيلية كبرى تضم آلاف العمال والموظفين. فإغفال العطلات يقود إلى تقديرات متفائلة بصورة زائفة فيما يتعلق بمواعيد تسليم المشاريع، مما يؤدي إلى غرامات تأخير تعاقدية وانهيار في جدولة التدفقات النقدية المتوقعة. كما يؤثر مباشرة على حساب معدلات احتراق الموارد (Burn Rates) ومعدلات استهلاك ساعات العمل المعيارية المسجلة في برمجيات تخطيط موارد المؤسسات (ERP Systems).

6. معالجة الأخطاء والتحقق من صحة المدخلات في بيئة VBA

6.1 إدارة أخطاء عدم تطابق أنواع البيانات (Type Mismatch)

من أكثر التحديات التقنية التي تواجه استدعاء دوال ورقة العمل عبر كود VBA هو الخطأ البرمجي الشهير المعروف باسم “عدم تطابق النوع” (Run-time error ’13’: Type Mismatch)، أو الخطأ الحسابي لمحرر إكسل (Run-time error ‘1004’: Method ‘NetworkDays’ of object ‘WorksheetFunction’ failed). تنشأ هذه الأخطاء عندما تصادف الدالة خلية تحتوي على نص أبجدي عشوائي، أو رمز خاطئ، أو قيمة فراغية ناتجة عن استيراد غير سليم للبيانات.

لمواجهة هذا الخلل وضمان مناعة الكود ضد الانهيار الفجائي أثناء المعالجة المتدفقة، يتعين تطبيق بروتوكول التحقق القبلي من صحة البيانات (Pre-Validation Protocol) باستخدام الدالة المنطقية IsDate(). تفحص هذه الدالة المدخلات قبل تمريرها وتتحقق مما إذا كانت تمثل تعبيراً زمنياً صالحاً للتحويل الحسابي، كما هو موضح في النموذج التالي:

If IsDate(ws.Range("A" & i).Value) And IsDate(ws.Range("B" & i).Value) Then
    ' التنفيذ الآمن للدالة البرمجية
    ws.Range("C" & i).Value = Application.WorksheetFunction.NetworkDays(ws.Range("A" & i).Value, ws.Range("B" & i).Value)
Else
    ' معالجة السجلات المعطوبة بأسلوب آمن
    ws.Range("C" & i).Value = "بيانات غير صالحة"
End If

يحمي هذا الإجراء الوقائي حلقة التكرار من التوقف القسري، ويتيح للمستخدم تحديد السجلات الشاذة بصرياً في ورقة العمل لتصحيحها لاحقاً دون إفساد معالجة بقية السجلات السليمة.

6.2 التعامل مع الترتيب الزمني المعكوس للتواريخ

يحدث في كثير من الحالات التشغيلية أن يقوم مدخل البيانات بعكس الترتيب المنطقي للتواريخ، فيضع تاريخ الإنجاز الفعلي في عمود البداية وتاريخ الانطلاق في عمود النهاية ($T_{start} > T_{\end}$). وكما أوضحنا في التحليل النظري، تستجيب دالة NetworkDays لهذا السيناريو بإرجاع قيمة عددية سالبة؛ فإذا كانت الفترة الطبيعية بين تاريخين هي 5 أيام عمل، فإن عكس المدخلات سينتج عنه الرقم (-5).

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

  1. استراتيجية التنبيه والرفض: التحقق من الشرط ws.Range("A" & i).Value > ws.Range("B" & i).Value، وتسجيل ملحوظة صريحة في الخلية تشير إلى وجود تناقض زمني في مدخلات السجل.
  2. استراتيجية التصحيح الذاتي التلقائي (Auto-Correction): استخدام متغير زمني وسيط لإعادة ترتيب التواريخ تصاعدياً قبل تمريرها للدالة، مع توفير مؤشر وصفي يوضح أنه تم عكس الترتيب للحفاظ على اتساق النتائج الرياضية الإيجابية.

6.3 بناء بنية قوية لاقتناص الأخطاء عبر عبارات On Error

يتطلب التطوير الاحترافي للأكواد البرمجية تأسيس بنية دفاعية متكاملة لاقتناص ومعالجة الاستثناءات التشغيلية المفاجئة عبر توظيف جمل On Error التوجيهية. توفر بيئة VBA طريقتين جوهريتين لاستدعاء دالة ورقة العمل، وينعكس الاختيار بينهما مباشرة على نمط إدارة الأخطاء:

  • الاستدعاء عبر Application.WorksheetFunction.NetworkDays: في هذا النمط، يؤدي أي خطأ حسابي في وسائط الدالة إلى إطلاق استثناء حرج يوقف الكود فوراً إذا لم تتم حمايته بجملة On Error GoTo ErrorHandler.
  • الاستدعاء المباشر عبر Application.NetworkDays: في هذا النمط المرن، يتجاوز إكسل إطلاق الاستثناء الحرج عند حدوث عطل في المعالجة، ويعيد بدلاً من ذلك قيمة خطأ خاصة من نوع Variant تسمى خطأ رقمي (CVErr)، يمكن فحصها بسلاسة تامة باستخدام الدالة البرمجية IsError() دون الحاجة لنقل مسار التنفيذ البرمجي إلى كتل معالجة معقدة.

توضح الشيفرة التالية التطبيق الهندسي لرصد الاستثناءات وتوجيهها لقسم المعالجة المركزية مع تسجيل الخطأ بدقة:

Public Sub SafeNetworkDaysExecution()
    On Error GoTo GlobalErrorHandler
    
    Dim ws As Worksheet
    Dim i As Long
    Set ws = ActiveSheet
    
    For i = 2 To 9
        ' فحص وجود أخطاء في المدخلات باستخدام الاستدعاء البديل المرن
        Dim result As Variant
        result = Application.NetworkDays(ws.Range("A" & i).Value, ws.Range("B" & i).Value)
        
        If IsError(result) Then
            ws.Range("C" & i).Value = "خطأ في الصيغة"
        Else
            ws.Range("C" & i).Value = result
        End If
    Next i
    
    Exit Sub

GlobalErrorHandler:
    MsgBox "حدث خطأ غير متوقع أثناء معالجة السجل رقم: " & i & vbCrLf & _
           "رقم الخطأ: " & Err.Number & vbCrLf & _
           "وصف الخطأ: " & Err.Description, vbCritical, "فشل أمني للنظام"
End Sub

7. تحسين الأداء البرمجي لمعالجة مجموعات البيانات الضخمة

7.1 تخفيض التفاعل المباشر مع واجهة التطبيق عبر المصفوفات في الذاكرة

تعد قراءة البيانات وكتابتها خلية تلو الأخرى (Cell-by-cell interaction) من أكثر العمليات استنزافاً لموارد المعالجة في تطبيقات VBA. ففي كل مرة يقوم فيها الكود بتنفيذ استدعاء مثل Range("A" & i).Value، يتم إحداث تبادل بيني مركب يستهلك دورات المعالج ويجبر إكسل على تحديث مراجع الواجهة الرسومية وهياكل المستندات المرتبطة.

لتخطي هذا العنق الزجاجي (Performance Bottleneck) عند التعامل مع آلاف الأسطر، تبرز المنهجية الأكاديمية القائمة على معالجة مصفوفات الذاكرة الداخلية (In-Memory Arrays). تنص هذه المنهجية على:

  1. تحميل كامل نطاق البيانات المدخلة بضربة واحدة من ورقة العمل إلى مصفوفة بيانات ثنائية الأبعاد مخزنة داخل ذاكرة الوصول العشوائي (RAM).
  2. إنشاء مصفوفة مخرجات موازية داخل الذاكرة لاستقبال النتائج الحسابية الناتجة عن تنفيذ دالة NetworkDays.
  3. إجراء العمليات الحسابية بالكامل عبر المرور التكراري فائق السرعة على عناصر المصفوفات في الذاكرة.
  4. إعادة تفريغ مصفوفة النتائج بالكامل في ورقة العمل دفعة واحدة (Single-operation Write) عبر إسناد المصفوفة إلى النطاق المستهدف.

تُقلص هذه التقنية زمن المعالجة الحسابية بمقدار يتجاوز 90% إلى 95% مقارنة بالقراءة والكتابة المباشرة في الخلايا، مما يحول معالجة عشرات الآلاف من السجلات من مسألة تستغرق دقائق طويلة إلى عملية تنتهي في أجزاء من الثانية.

7.2 تعطيل العمليات التفاعلية أثناء تنفيذ الماكرو

بالتوازي مع استخدام مصفوفات الذاكرة، توفر لغة VBA حزمة من الخصائص العامة للتحكم في سلوك التطبيق (Application-level Properties) التي تسهم في مضاعفة سرعة التنفيذ عند تعطيلها مؤقتاً أثناء تشغيل العمليات المعقدة:

  • Application.ScreenUpdating = False: يقوم هذا الأمر بتجميد تحديث الشاشة والواجهة الرسومية للمصنف. فبدلاً من إعادة رسم الخلايا مع كل مخرج جديد، يتوقف إكسل عن التحديث البصري حتى تكتمل كافة الحسابات، مما يوفر جهداً هائلاً لمعالج الرسوميات والمعالج الرئيسي.
  • Application.Calculation = xlCalculationManual: يوقف إعادة الحساب التلقائي لمعادلات المصنف. في المصنفات الضخمة التي تحتوي على مئات الصيغ المترابطة، يؤدي تغيير قيمة خلية واحدة إلى إعادة حساب شجرة الصيغ بالكامل تلقائياً، مما يشل سرعة الكود. بتعطيل هذه الخاصية، نضمن عدم استنزاف موارد الجهاز حتى نهاية المعالجة.
  • Application.EnableEvents = False: يمنع إطلاق الأحداث التلقائية للمصنف (مثل أحداث Worksheet_Change)، مما يتفادى تشغيل أكواد متداخلة غير مقصودة أثناء كتابة النتائج.

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

7.3 جعل حدود الحلقة التكرارية ديناميكية بالكامل

إن تحديد نطاق السجلات الحسابية بقيم رقمية ثابتة (Hardcoded Boundaries) كما في المثال التجريبي الأولي (For i = 2 To 9) يمثل قصوراً كبيراً في هندسة البرمجيات، إذ لا يتناسب مع طبيعة ملفات الأعمال المتغيرة يومياً بالإضافة والحذف. لذلك، يجب برمجة حدود الحلقة التكرارية لتكون ديناميكية بالكامل وقادرة على استكشاف آخر سطر نشط في ورقة العمل تلقائياً.

يتحقق هذا الاستكشاف الديناميكي باستخدام الخاصية End(xlUp)، التي تحاكي برمجياً وقوف المستخدم في الخلية السفلية القصوى للعمود ثم ضغطه على الاختصار Ctrl + Up Arrow للارتطام بآخر خلية تحتوي على بيانات فعلية، كما هو موضح أدناه:

Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

If lastRow >= 2 Then
    For i = 2 To lastRow
        ' تنفيذ الحسابات على النطاق المتغير بأمان تام
    Next i
End If

تمنح هذه الصياغة الماكرو استقلالية تشغيلية كاملة؛ حيث يتكيف الروتين ذاتياً مع إضافة عشرات أو مئات الأسطر الجديدة دون أي حاجة للتدخل البشري لتعديل الشفرة المصدرية.

8. مقارنة منهجية بين دالتي NetworkDays و NetworkDays.INTL في VBA

8.1 حدود دالة NetworkDays الكلاسيكية والافتراضات الثابتة

على الرغم من البساطة والأداء العالي اللذين تتمتع بهما دالة NetworkDays الكلاسيكية، إلا أنها تعاني من قيد هيكلي صارم يحد من استخدامها في العديد من الأنظمة الاقتصادية والتشريعية العالمية؛ حيث تتبنى الدالة فرضية حتمية وغير قابلة للتغيير بأن عطلة نهاية الأسبوع تقتصر حصراً على يومي السبت والأحد.

يمثل هذا القيد قصوراً جوهرياً عند تطبيق الدالة في بيئات العمل التي تعتمد تقاويم مختلفة، لا سيما في أسواق الشرق الأوسط والعديد من الدول العربية والإسلامية التي تطبق عطلات نهاية أسبوع تشمل الجمعة والسبت، أو في القطاعات المتخصصة كالمستشفيات، وشركات الطيران، ومنافذ البيع بالتجزئة، وقطاعات الأمن والسلامة التي تعتمد جداول نوبات بنظام يوم راحة واحد متغير (كأن يكون يوم الإثنين أو الأحد فقط). في هذه الحالات، يفشل الاعتماد على الدالة الكلاسيكية وينتج عنه حسابات غير متوافقة تشريعياً وتنظيمياً مع لوائح العمل الفعلية.

8.2 مزايا ومرونة دالة WorksheetFunction.NetworkDays_Intl

لتجاوز هذا القصور التاريخي، قدمت مايكروسوفت ابتداءً من إصدار Excel 2010 الدالة الموسعة NetworkDays.INTL (وتُستدعى في بيئة الأكواد بالصيغة: Application.WorksheetFunction.NetworkDays_Intl). توفر هذه الدالة معاملين متقدمين إضافيين لمعالجة أنماط عطلات نهاية الأسبوع وتخصيصها بدقة متناهية:

  1. معامل نمط عطلة نهاية الأسبوع الرقمي (Weekend Code): يسمح بتمرير رقم كودي يعبر عن أيام الراحة، مثل الرقم 7 لعطلة (الجمعة والسبت)، أو الرقم 11 لليوم الواحد (الأحد فقط)، وهكذا لكافة التباديل الممكنة.
  2. سلاسل الأنماط النصية الثنائية (Binary Mask Strings): تتيح الدالة تمرير سلسلة نصية مكونة بدقة من 7 خانات ثنائية (أصفار وآحاد) لتمثيل أيام الأسبوع السبعة بدءاً من يوم الإثنين وحتى الأحد، حيث يمثل الرقم (1) يوم عطلة، ويمثل الرقم (0) يوم عمل. على سبيل المثال، فإن السلسلة "0000110" تحدد يومي الجمعة والسبت كأيام عطلة رسمية، بينما تسمح السلسلة "1010100" بإنشاء جداول عمل مخصصة بالغة التعقيد، مما يمنح المطور تحكماً مطلقاً في هندسة التوقيتات.

يوضح المثال البرمجي التالي كيفية استدعاء الدالة المتقدمة لاحتساب أيام العمل وفق نظام عطلة (الجمعة والسبت):

Dim netDaysIntl As Long
' استخدام الكود الرقمي 7 للدلالة على عطلة الجمعة والسبت
netDaysIntl = Application.WorksheetFunction.NetworkDays_Intl( _
    ws.Range("A2").Value, _
    ws.Range("B2").Value, _
    7, _
    ws.Range("E2:E5") _
)

8.3 جدول المفاضلة المعيارية لاختيار الدالة الأنسب برمجياً

يوضح الجدول المقارن التالي الفروق الجوهرية والتشغيلية بين الدالتين لاختيار الأداة الأنسب بحسب متطلبات بيئة العمل:

المعيار البرمجي والتشغيلي دالة NetworkDays الكلاسيكية دالة NetworkDays.INTL المتقدمة
التوافق التاريخي مع الإصدارات متوافقة مع كافة إصدارات إكسل القديمة والحديثة (إصدارات 2000 فما بعدها). تتطلب حصرياً إصدار إكسل 2010 أو أحدث، وتخفق على الإصدارات الأقدم.
مرونة عطلة نهاية الأسبوع ثابتة قطعياً (السبت والأحد فقط). مرنة بالكامل عبر أكواد جاهزة أو سلاسل ثنائية مخصصة من 7 خانات.
ملاءمة بيئات العمل العربية ضعيفة (تتطلب معالجات حسابية تعويضية شاقة لتعديل الإزاحة). مثالية ومتطابقة تلقائياً مع نظام العمل العربي (الجمعة/السبت).
التعقيد التركيبي وسهولة الصيانة بسيطة للغاية وتتطلب وسيطين إلى ثلاثة وسائط كحد أقصى. تتطلب إدراج وتوثيق معامل العطلة الأسبوعية لمنع حدوث التباس للمراجعين.
السرعة الحاسوبية والاستهلاك أسرع بنسبة ضئيلة جداً لتثبيت منطق فحص أيام الأسبوع داخلياً. فائقة السرعة ومحسنة مع إضافة طبقة تحليلية لمعامل العطلة المخصص.

9. تحويل الإجراء إلى دالة مخصصة (UDF) قابلة لإعادة الاستخدام

9.1 تصميم وتطوير دالة معرفة من قبل المستخدم (User-Defined Function)

على الرغم من فاعلية الإجراءات الفرعية من نوع Sub في تنفيذ المعالجة الدفعية الشاملة وتوليد التقارير عبر نقرة زر، إلا أنها تفتقر إلى المرونة التفاعلية المباشرة داخل شبكة الخلايا. يتيح الانتقال إلى برمجة الدوال المخصصة (User-Defined Functions – UDFs) للمطور بناء دالة هجينة تجمع بين المنطق الحسابي لـ VBA وقابلية الاستدعاء المباشر من شريط الصيغ في إكسل كأي دالة قياسية مدمجة (مثل SUM أو VLOOKUP).

يتحول الإجراء في هذا السياق من روتين تنفيذي مغلق إلى دالة وظيفية تستقبل المعاملات عبر رأس الإجراء وتعيد القيمة الناتجة باسم الدالة نفسها، كما يتجلى في البناء التالي:

Option Explicit

Public Function CustomWorkDays( _
    ByVal StartDate As Date, _
    ByVal EndDate As Date, _
    Optional ByVal Holidays As Range = Nothing _
) As Variant

    On Error GoTo FunctionError
    
    ' التحقق من صحة الترتيب الزمني
    If StartDate > EndDate Then
        CustomWorkDays = "خطأ: تاريخ البدء يتجاوز تاريخ الانتهاء"
        Exit Function
    End If
    
    ' فحص تمرير وسيطة العطلات الرسمية الاختيارية
    If Holidays Is Nothing Then
        CustomWorkDays = Application.WorksheetFunction.NetworkDays(StartDate, EndDate)
    Else
        CustomWorkDays = Application.WorksheetFunction.NetworkDays(StartDate, EndDate, Holidays)
    End If
    
    Exit Function

FunctionError:
    CustomWorkDays = CVErr(xlErrValue)
End Function

تتيح هذه الدالة للمستخدم النهائي كتابة الصيغة =CustomWorkDays(A2, B2, $E$2:$E$5) مباشرة في خلايا ورقة العمل، مع الاستفادة التلقائية من شروط الحماية والتحقق الداخلي المضمنة برمجياً.

9.2 تأمين مدخلات الدالة المخصصة وضمان استقرارها

يتطلب بناء الدوال المعرفة استقراراً صارماً في إدارة المتغيرات لضمان عدم انهيار الدالة عند سحبها وتطبيقها على آلاف الخلايا. تتمثل الخطوة المحورية الأولى في التصريح الصريح عن أنواع البيانات لجميع المعاملات المدخلة عبر الكلمة المفتاحية ByVal؛ لضمان تمرير القيم الفعلية للخلايا دون المساس بالأصول المرجعية في الذاكرة.

من المسائل التقنية الدقيقة في برمجة الدوال المخصصة مسألة إعادة الحساب التلقائي (Volatility). إذا احتوت الدالة على الكلمة التوجيهية Application.Volatile True، فإن إكسل سيقوم بإعادة حسابها مع أي حركة تتم في أي خلية بالمصنف حتى لو لم تتغير مدخلات الدالة نفسها، وهو ما يسبب بطئاً شديداً في الأداء. لذلك، يجب تجنب إدراج هذه الخاصية في دوال احتساب أيام العمل، والاكتفاء بالسلوك الافتراضي الذي يعيد حساب الدالة حصراً إذا طرأ تغيير على إحدى خلايا المدخلات المرتبطة بها (الخلايا التابعة – Precedents).

9.3 مقارنة الكفاءة بين الروتين التكراري والدالة المخصصة

تخضع المفاضلة بين الاعتماد على روتين تكراري دفعي (Batch Macro) أو نشر دوال مخصصة (UDFs) عبر آلاف الخلايا لمعايير هندسة البرمجيات وإدارة الموارد المتاحة:

  • استهلاك موارد المعالج والذاكرة: تتفوق الإجراءات الدفعية المعتمدة على مصفوفات الذاكرة تفوقاً ساحقاً على الدوال المخصصة عند التعامل مع مجموعات البيانات الكبرى. إن وجود 50,000 خلية تحتوي كل منها على دالة مخصصة يستلزم استدعاء محرك VBA 50,000 مرة عند فتح المصنف أو تعديل مصفوفة العطلات، مما يؤدي إلى تجمد التطبيق لعدة ثوانٍ أو دقائق، في حين يقوم الماكرو الدفعي بإنجاز نفس الحسابات دون ترك صيغ حية تثقل كاهل الذاكرة.
  • سهولة الصيانة وتحديث التقارير: توفر الدوال المخصصة تفاعلية مريحة للمستخدم غير التقني؛ إذ تُحدث النتائج تلقائياً بمجرد تعديل تاريخ البدء دون الحاجة لتذكر الضغط على زر تشغيل الماكرو.
  • القرار الهندسي الأمثل: يُنصح باستخدام الدوال المخصصة في النماذج التحليلية المحدودة وأوراق العمل التفاعلية الفردية، بينما يُعتمد الإجراء الدفعي التكراري دون منازع في قواعد البيانات التشغيلية الضخمة وتقارير لوحات المعلومات (Dashboards) الدورية.

10. أفضل الممارسات البرمجية والتوصيات المنهجية للتطبيق العملي

10.1 التوثيق المعياري وتصميم الأكواد النظيفة (Clean Code)

تمثل كتابة الأكواد النظيفة (Clean Code) الركيزة الأولى لضمان استدامة الأنظمة البرمجية وسهولة صيانتها عبر الفرق التقنية المتعددة. يتطلب ذلك الالتزام الصارم بمعايير التسمية القياسية المعتمدة عالمياً (Hungarian Notation)، كتسمية المتغيرات برموز توضح نوعها، مثل: dtStart لمتغيرات التواريخ، و rngHolidays لكائنات النطاقات، و lRowIndex للمتغيرات العددية الطويلة من نوع Long.

علاوة على ذلك، يجب مراعاة التنسيق البصري للكود واستخدام المسافات البادئة المنتظمة (Indentation) بمقدار 4 مسافات لكل كتلة شرطية أو حلقة تكرارية، مما يعزز المقروئية ويقلل زمن تتبع الأخطاء البرمجية. كما ينبغي تضمين كتل التوثيق التفسيرية (Docstrings) في مقدمة كل إجراء لتوضيح آليات عمل الخوارزمية، والفرضيات التقويمية المعتمدة، وقيود الاستخدام، وسياقات الربط المعماري مع أوراق العمل الأخرى.

10.2 التحقق من صحة وموثوقية مخرجات العمليات البرمجية

قبل اعتماد ونشر أي كود برمجي يعتمد على دالة NetworkDays في بيئة الإنتاج التشغيلي للمؤسسة، يتعين إخضاعه لبروتوكول اختبارات وحدوية صارم (Unit Testing). يشمل هذا الاختبار إعداد ورقة بيانات معيارية تحتوي على حالات حافة تقويمية حرجة (Boundary & Edge Cases)، مثل:

  • فترات تبدأ وتنتهي في نفس اليوم (يوم عمل عادي، مقارنة بيوم عطلة نهاية أسبوع).
  • فترات تمتد بالكامل داخل عطلة نهاية أسبوع قياسية (السبت إلى الأحد)، حيث يجب أن تعيد الدالة القيمة الصفرية 0 دون التباس.
  • فترات تتضمن عطلات رسمية متعددة تتزامن إحداها عمداً مع عطلة نهاية الأسبوع للتأكد من عدم خصم اليوم مرتين.
  • فترات زمنية طويلة تمتد لعدة سنوات للتحقق من سلامة معالجة السنوات الكبيسة (Leap Years) واحتساب يوم 29 فبراير بصورة سليمة.

يتم التحقق من مطابقة مخرجات الكود الحسابية مع نتائج الحسابات اليدوية الموثقة، وتأسيس نقاط تدقيق رقابية (Audit Trails) في ورقة العمل لتنبيه المشرفين في حال ظهور أي انحرافات غير متوقعة في المخرجات.

10.3 إرشادات الدمج مع أنظمة التخطيط وإدارة المشروعات

لا تعمل الشيفرات البرمجية المنظمة لحساب أيام العمل الصافية كجزر معزولة، بل تشكل حجر الزاوية للمنظومات الأوسع لتخطيط المشروعات وإدارة سلاسل القيمة. عند ربط مخرجات الدالة بحسابات المسار الحرج (Critical Path Method)، يتم استثمار صافي أيام العمل المحسوبة لتحديد التواريخ المبكرة والمتأخرة للبدء والانتهاء (Early/Late Start & Finish)، مما يتيح التحديد الصارم لنقاط الاختناق التشغيلي ومناطق الفائض الزمني (Float/Slack Time).

كما تشكل هذه المخرجات البرمجية المدخلات الرقمية الأساسية لبناء وتحديث مخططات جانت المؤتمتة (Automated Gantt Charts) من خلال التنسيق الشرطي البرمجي؛ حيث يتم تحويل أيام العمل الصافية إلى أطوال كتل زمنية بيانية تعكس الحجم الحقيقي للجهد البشري المطلوب دون تضخيم ناتج عن العطلات الرسمية. يضمن هذا التكامل الهندسي بين بيئة VBA وأدوات إكسل التخطيطية توفير رؤية استراتيجية واضحة ودقيقة تسهم في الالتزام بالجداول الزمنية، وتحقيق أقصى درجات الكفاءة المؤسسية والربحية التشغيلية المستدامة.

المراجع

تستند كافة المعلومات والحقائق التقنية والبرمجية الواردة في هذا الدليل الأكاديمي إلى الوثائق والمراجع التوثيقية المعتمدة التالية:

  • Microsoft Corporation. (n.d.). WorksheetFunction.NetworkDays method (Excel). Microsoft Learn. Retrieved from https://learn.microsoft.com/en-us/office/vba/api/excel.worksheetfunction.networkdays
  • Microsoft Corporation. (n.d.). WorksheetFunction.NetworkDays_Intl method (Excel). Microsoft Learn. Retrieved from https://learn.microsoft.com/en-us/office/vba/api/excel.worksheetfunction.networkdays_intl
  • Microsoft Corporation. (n.d.). NETWORKDAYS function. Microsoft Support. Retrieved from https://support.microsoft.com/en-us/office/networkdays-function-48e717bf-a7ab-495f-968b-3522137eb8ee
  • Statology. (n.d.). How to Use NetworkDays in VBA (With Example). Statology. Retrieved from https://www.statology.org/vba-networkdays/
  • Walkenbach, J. (2015). Excel 2016 Power Programming with VBA. John Wiley & Sons.
★

تقييم هذا المحتوى

5.0 / 5 • 7 تقييمات

اقتباس هذا المقال

looti, M. (2026, أكتوبر 23). كيفية استخدام NetworkDays في VBA (مع مثال). عرب سايكلوجي. https://arabpsychology.com/statistics/how-to-use-networkdays-in-vba-with-example/
looti, Mohammed. “كيفية استخدام NetworkDays في VBA (مع مثال).” عرب سايكلوجي, 23 أكتوبر 2026, https://arabpsychology.com/statistics/how-to-use-networkdays-in-vba-with-example/.
looti, Mohammed. “كيفية استخدام NetworkDays في VBA (مع مثال).” عرب سايكلوجي. أكتوبر 23, 2026. https://arabpsychology.com/statistics/how-to-use-networkdays-in-vba-with-example/.