كيفية تنسيق نطاقات التواريخ مثل 1 يناير - 5 يناير
استخدام جافا سكريبت لعرض نطاقات التواريخ بتنسيق مناسب للغة المحلية وإزالة ذكية للتكرار
مقدمة
تظهر نطاقات التواريخ في جميع أنحاء تطبيقات الويب. تعرض أنظمة الحجز التوفر من 1 يناير إلى 5 يناير، وتعرض تقويمات الفعاليات المؤتمرات متعددة الأيام، وتعرض لوحات التحليلات البيانات لفترات زمنية محددة، وتغطي التقارير الأرباع المالية أو نطاقات التواريخ المخصصة. توضح هذه النطاقات أن شيئًا ما ينطبق على جميع التواريخ بين نقطتي نهاية.
عندما تقوم بتنسيق نطاقات التواريخ يدويًا عن طريق دمج تاريخين منسقين بشرطة، فإنك تنشئ مخرجات مطولة بلا داعٍ. لا يحتاج النطاق من 1 يناير 2024 إلى 5 يناير 2024 إلى تكرار الشهر والسنة في التاريخ الثاني. تنقل المخرجات "1 - 5 يناير، 2024" نفس المعلومات بشكل أكثر إيجازًا من خلال حذف المكونات المكررة.
توفر جافا سكريبت طريقة formatRange() في Intl.DateTimeFormat للتعامل مع تنسيق نطاق التاريخ تلقائيًا. تحدد هذه الطريقة مكونات التاريخ التي يجب تضمينها في كل جزء من النطاق، وتطبق الاصطلاحات الخاصة باللغة المحلية للفواصل والتنسيق مع إزالة التكرار غير الضروري.
لماذا تحتاج نطاقات التواريخ إلى تنسيق ذكي
تتطلب نطاقات التواريخ المختلفة مستويات مختلفة من التفاصيل. يحتاج النطاق ضمن نفس الشهر إلى معلومات أقل من النطاق الذي يمتد لعدة سنوات. يعتمد التنسيق الأمثل على مكونات التاريخ التي تختلف بين تواريخ البداية والنهاية.
بالنسبة للنطاق ضمن نفس اليوم، تحتاج فقط إلى إظهار فرق الوقت: "10:00 صباحًا - 2:00 مساءً". تكرار التاريخ الكامل لكلا الوقتين لا يضيف أي معلومات.
بالنسبة للنطاق ضمن نفس الشهر، تعرض الشهر مرة واحدة وتسرد كلا رقمي اليوم: "1-5 يناير، 2024". تضمين "يناير" مرتين يجعل المخرجات أصعب في القراءة دون إضافة وضوح.
بالنسبة للنطاق الذي يمتد عبر شهور مختلفة في نفس السنة، تعرض كلا الشهرين ولكن يمكن حذف السنة من التاريخ الأول: "25 ديسمبر، 2024 - 2 يناير، 2025" يحتاج إلى المعلومات الكاملة، ولكن "15 يناير - 20 فبراير، 2024" يمكن حذف السنة من التاريخ الأول في بعض اللغات المحلية.
بالنسبة للنطاقات التي تمتد لعدة سنوات، يجب تضمين السنة لكلا التاريخين: "1 ديسمبر، 2023 - 15 مارس، 2024".
يتطلب التنفيذ اليدوي لهذه القواعد التحقق من مكونات التاريخ التي تختلف وبناء سلاسل التنسيق وفقًا لذلك. تطبق اللغات المحلية المختلفة أيضًا هذه القواعد بشكل مختلف، باستخدام فواصل واصطلاحات ترتيب مختلفة. تغلف طريقة formatRange() هذا المنطق.
استخدام formatRange لتنسيق نطاقات التواريخ
تقبل طريقة formatRange() كائنين من نوع Date وتُرجع سلسلة نصية منسقة. قم بإنشاء نسخة من Intl.DateTimeFormat مع اللغة المحلية والخيارات المطلوبة، ثم استدعِ formatRange() مع تواريخ البداية والنهاية.
const formatter = new Intl.DateTimeFormat("en-US");
const start = new Date(2024, 0, 1);
const end = new Date(2024, 0, 5);
console.log(formatter.formatRange(start, end));
// Output: "1/1/24 – 1/5/24"
يطبق المنسق تنسيق التاريخ الافتراضي للإنجليزية الأمريكية على كلا التاريخين ويربط بينهما بشرطة متوسطة. بالنسبة للتواريخ ضمن نفس الشهر، لا يزال الإخراج يُظهر كلا التاريخين بالكامل لأن التنسيق الافتراضي قصير جدًا.
يمكنك تحديد مكونات التاريخ التي تريد تضمينها باستخدام نفس الخيارات المتاحة لتنسيق التاريخ العادي.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const start = new Date(2024, 0, 1);
const end = new Date(2024, 0, 5);
console.log(formatter.formatRange(start, end));
// Output: "January 1 – 5, 2024"
الآن يحذف المنسق بذكاء الشهر والسنة من التاريخ الثاني لأنهما يتطابقان مع التاريخ الأول. يُظهر الإخراج فقط رقم اليوم للتاريخ النهائي، مما يجعل النطاق أكثر وضوحًا.
كيف تُحسّن formatRange إخراج نطاق التواريخ
تفحص طريقة formatRange() كلا التاريخين وتحدد المكونات المختلفة. وتضمن فقط المكونات الضرورية في كل جزء من النطاق.
بالنسبة للتواريخ في نفس الشهر والسنة، يظهر فقط يوم النهاية في الجزء الثاني.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(formatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "January 1 – 5, 2024"
console.log(formatter.formatRange(
new Date(2024, 0, 15),
new Date(2024, 0, 20)
));
// Output: "January 15 – 20, 2024"
يُظهر كلا النطاقين الشهر والسنة مرة واحدة، مع أرقام الأيام فقط متصلة بفاصل النطاق.
بالنسبة للتواريخ في أشهر مختلفة من نفس السنة، يظهر كلا الشهرين ولكن تظهر السنة مرة واحدة فقط.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(formatter.formatRange(
new Date(2024, 0, 15),
new Date(2024, 1, 20)
));
// Output: "January 15 – February 20, 2024"
يتضمن المنسق اسمي الشهرين ولكنه يضع السنة في النهاية، مطبقًا إياها على النطاق بأكمله.
بالنسبة للتواريخ التي تمتد عبر سنوات مختلفة، يظهر كلا التاريخين بالكامل.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(formatter.formatRange(
new Date(2023, 11, 25),
new Date(2024, 0, 5)
));
// Output: "December 25, 2023 – January 5, 2024"
يتضمن كل تاريخ سنته الكاملة لأن السنوات مختلفة. لا يمكن للمنسق حذف أي من السنتين دون خلق غموض.
تنسيق نطاقات التاريخ والوقت
عندما يتضمن التنسيق الخاص بك مكونات زمنية، تطبق طريقة formatRange() نفس الحذف الذكي على حقول الوقت.
بالنسبة للأوقات في نفس اليوم، تختلف فقط مكونات الوقت في المخرجات.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 1, 14, 30);
console.log(formatter.formatRange(start, end));
// Output: "January 1, 2024, 10:00 AM – 2:30 PM"
يظهر التاريخ مرة واحدة، متبوعًا بنطاق الوقت. يدرك المنسق أن تكرار التاريخ والوقت الكامل للنهاية لن يضيف أي معلومات مفيدة.
بالنسبة للأوقات في أيام مختلفة، تظهر قيم التاريخ والوقت الكاملة لكليهما.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 2, 14, 30);
console.log(formatter.formatRange(start, end));
// Output: "January 1, 2024, 10:00 AM – January 2, 2024, 2:30 PM"
يظهر كلا التاريخين والوقتين لأنهما يمثلان أيامًا مختلفة. لا يمكن للمنسق حذف أي مكونات بأمان.
تنسيق نطاقات التاريخ في لغات مختلفة
يتكيف تنسيق النطاق مع اتفاقيات كل لغة لترتيب مكونات التاريخ، والفواصل، والمكونات التي يجب حذفها.
const enFormatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(enFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "January 1 – 5, 2024"
const deFormatter = new Intl.DateTimeFormat("de-DE", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(deFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "1.–5. Januar 2024"
const jaFormatter = new Intl.DateTimeFormat("ja-JP", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(jaFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "2024年1月1日~5日"
اللغة الإنجليزية تضع الشهر أولاً وتعرض السنة في النهاية. الألمانية تضع أرقام الأيام أولاً مع نقاط، ثم اسم الشهر، ثم السنة. اليابانية تستخدم ترتيب السنة-الشهر-اليوم وعلامة الموجة (~) كفاصل للنطاق. تطبق كل لغة اتفاقياتها الخاصة لتحديد المكونات التي تظهر مرة واحدة مقابل مرتين.
تمتد هذه الاختلافات إلى نطاقات عبر الأشهر.
const enFormatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(enFormatter.formatRange(
new Date(2024, 0, 15),
new Date(2024, 1, 20)
));
// Output: "January 15 – February 20, 2024"
const deFormatter = new Intl.DateTimeFormat("de-DE", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(deFormatter.formatRange(
new Date(2024, 0, 15),
new Date(2024, 1, 20)
));
// Output: "15. Januar – 20. Februar 2024"
const frFormatter = new Intl.DateTimeFormat("fr-FR", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(frFormatter.formatRange(
new Date(2024, 0, 15),
new Date(2024, 1, 20)
));
// Output: "15 janvier – 20 février 2024"
تعرض اللغات الثلاث أسماء الشهرين ولكن بمواضع مختلفة بالنسبة لأرقام الأيام. تتعامل المنسقات مع هذه الاختلافات تلقائيًا.
تنسيق نطاقات التواريخ بأنماط مختلفة
يمكنك استخدام خيار dateStyle للتحكم في طول التنسيق الإجمالي، تمامًا كما هو الحال مع تنسيق التاريخ الفردي.
const shortFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "short"
});
console.log(shortFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "1/1/24 – 1/5/24"
const mediumFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium"
});
console.log(mediumFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "Jan 1 – 5, 2024"
const longFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "long"
});
console.log(longFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "January 1 – 5, 2024"
const fullFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "full"
});
console.log(fullFormatter.formatRange(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
));
// Output: "Monday, January 1 – Friday, January 5, 2024"
نمط short ينتج تواريخ رقمية ولا يطبق الحذف الذكي لأن التنسيق مضغوط بالفعل. أنماط medium وlong تختصر أو تكتب الشهر بالكامل وتحذف المكونات المتكررة. نمط full يتضمن أسماء أيام الأسبوع لكلا التاريخين.
استخدام formatRangeToParts للتنسيق المخصص
تُرجع طريقة formatRangeToParts() مصفوفة من الكائنات التي تمثل مكونات النطاق المنسق. هذا يسمح لك بتنسيق أو معالجة أجزاء فردية من مخرجات النطاق.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const parts = formatter.formatRangeToParts(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
);
console.log(parts);
المخرجات هي مصفوفة من الكائنات، كل منها يحتوي على خصائص type وvalue وsource.
[
{ type: "month", value: "January", source: "startRange" },
{ type: "literal", value: " ", source: "startRange" },
{ type: "day", value: "1", source: "startRange" },
{ type: "literal", value: " – ", source: "shared" },
{ type: "day", value: "5", source: "endRange" },
{ type: "literal", value: ", ", source: "shared" },
{ type: "year", value: "2024", source: "shared" }
]
خاصية type تحدد المكون: الشهر، اليوم، السنة، أو النص الحرفي. خاصية value تحتوي على النص المنسق. خاصية source تشير إلى ما إذا كان المكون ينتمي إلى تاريخ البداية، تاريخ النهاية، أو مشترك بينهما.
يمكنك استخدام هذه الأجزاء لإنشاء HTML مخصص مع تنسيق لمكونات مختلفة.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const parts = formatter.formatRangeToParts(
new Date(2024, 0, 1),
new Date(2024, 0, 5)
);
let html = "";
parts.forEach(part => {
if (part.type === "month") {
html += `<span class="month">${part.value}</span>`;
} else if (part.type === "day") {
html += `<span class="day">${part.value}</span>`;
} else if (part.type === "year") {
html += `<span class="year">${part.value}</span>`;
} else if (part.type === "literal" && part.source === "shared" && part.value.includes("–")) {
html += `<span class="separator">${part.value}</span>`;
} else {
html += part.value;
}
});
console.log(html);
// Output: <span class="month">January</span> <span class="day">1</span><span class="separator"> – </span><span class="day">5</span>, <span class="year">2024</span>
تحافظ هذه التقنية على التنسيق الخاص باللغة مع السماح بالتنسيق المرئي المخصص.
ماذا يحدث عندما تتساوى التواريخ
عندما تمرر نفس التاريخ لكل من معلمتي البداية والنهاية، فإن formatRange() تُخرج تاريخًا منسقًا واحدًا بدلاً من نطاق.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2024, 0, 1);
console.log(formatter.formatRange(date, date));
// Output: "January 1, 2024"
يتعرف المنسق على أن النطاق ذو نقاط النهاية المتطابقة ليس نطاقًا حقيقيًا ويقوم بتنسيقه كتاريخ واحد. ينطبق هذا السلوك حتى عندما تكون كائنات Date عبارة عن نسخ مختلفة لها نفس القيمة.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 1, 10, 0);
console.log(formatter.formatRange(start, end));
// Output: "January 1, 2024"
على الرغم من أن هذه كائنات Date منفصلة، إلا أنها تمثل نفس التاريخ والوقت. يُخرج المنسق تاريخًا واحدًا لأن النطاق له مدة صفرية عند مستوى دقة خيارات التنسيق. نظرًا لأن التنسيق لا يتضمن مكونات الوقت، فإن الأوقات غير ذات صلة وتعتبر التواريخ متساوية.
متى تستخدم formatRange مقابل التنسيق اليدوي
استخدم formatRange() عند عرض نطاقات التاريخ للمستخدمين. ينطبق هذا على نطاقات تواريخ الحجز، ومدة الأحداث، وفترات التقارير، ونوافذ التوفر، أو أي فترات زمنية أخرى. تضمن هذه الطريقة التنسيق الصحيح الخاص باللغة المحلية والحذف الأمثل للمكونات.
تجنب استخدام formatRange() عندما تحتاج إلى عرض تواريخ متعددة غير مرتبطة. يجب أن تستخدم قائمة المواعيد النهائية مثل "1 يناير، 15 يناير، 1 فبراير" استدعاءات format() العادية لكل تاريخ بدلاً من معاملتها كنطاقات.
تجنب أيضًا استخدام formatRange() عند عرض المقارنات أو الاختلافات بين التواريخ. إذا كنت تعرض مدى تقدم أو تأخر تاريخ واحد مقارنة بآخر، فهذا يمثل حساب وقت نسبي بدلاً من نطاق.