رفتن به متن راهنما
همه‌ی راهنماها

تقویم تعطیلات

با HolidayCalendar تعطیلات را با رؤیت هلال و تقویم سازمان خودتان تطبیق بدهید. جابه‌جایی روز، شروع ماه قمری، افزودن و حذف تعطیلی، و دیدن منبع هر تاریخ.

برنامه RTLY-Kit 0.2.0آخرین بررسی زمان خواندن 8 دقیقه

در این صفحه

چرا این کلاس هست

در ایران تاریخ مناسبت‌های مذهبی را رؤیت هلال تعیین می‌کند. جدول ام‌القری یک تخمین می‌دهد که ۰ تا ۲ روز با اعلام رسمی فرق دارد. برای همین کتابخانه تاریخ‌های رسمی سال‌های ۱۳۹۴ و ۱۳۹۶ تا ۱۴۰۵ را دارد (برای هر سال دو منبع). برای ۱۳۸۰ تا ۱۳۹۳ و ۱۳۹۵ فقط تاریخ‌ها را داریم و بقیهٔ سال‌ها تخمین است.

کلاس RtlyKit\Holiday\HolidayCalendar به شما اجازه می‌دهد خودتان هم دخالت کنید. وقتی هلال دیده شد، تاریخ واقعی را بدهید. اگر سازمانتان روز خاصی را تعطیل کرده، اضافه‌اش کنید. هر تغییر یک تقویم تازه می‌سازد و چیزی سراسری عوض نمی‌شود. کلاس ساده IranHolidays که در تعطیلات دیدید، از همین کلاس با تنظیمات پیش‌فرض استفاده می‌کند.

تاریخ‌ها از کجا می‌آیند

برای سال‌های جلالی ۱۳۹۴ و ۱۳۹۶ تا ۱۴۰۵ تاریخ‌های رسمی داریم، با دو منبع برای هر سال. برای ۱۳۸۰ تا ۱۳۹۳ و ۱۳۹۵ فقط تاریخ‌ها را از یک منبع گزارش‌شده داریم. بقیهٔ سال‌ها تخمین از جدول ام‌القری است. منبع‌ها در دقت و داده آمده‌اند.

یک تقویم از پیش‌فرض‌ها بسازید و بپرسید هر سال از کجا آمده است:

PHP
<?php
require 'vendor/autoload.php';

use RtlyKit\Holiday\HolidayCalendar;
use RtlyKit\Holiday\IranHolidays;

$cal = HolidayCalendar::default();

echo $cal->sourceOf(1405)->name, "\n";   // Official
echo $cal->sourceOf(1395)->name, "\n";   // Reported
echo $cal->sourceOf(1406)->name, "\n";   // Estimated

echo implode(' | ', $cal->getTitles(1405, 1, 1)), "\n";   // جشن نوروز | عید فطر

مقدار sourceOf() یکی از این سه است:

مقدارمعنا
HolidaySource::Officialتاریخ‌های رسمی، با دو منبع (۱۳۹۴ و ۱۳۹۶ تا ۱۴۰۵)
HolidaySource::Reportedفقط تاریخ‌ها، از یک منبع (۱۳۸۰ تا ۱۳۹۳ و ۱۳۹۵). فهرست مناسبت‌ها در این سال‌ها کامل نیست
HolidaySource::Estimatedتخمین از جدول ام‌القری

کلاس IranHolidays هم همین را دارد: IranHolidays::calendar() تقویم پیش‌فرض را می‌دهد و IranHolidays::sourceOf($year) منبع آن سال را.

آموزش کوتاه

چهار کار رایج، یکی‌یکی. همه با $cal = HolidayCalendar::default(); شروع می‌شوند.

۱. جابه‌جایی همهٔ تعطیلات اسلامی

اگر می‌بینید تخمین، چند ماه پشت‌سرهم یک روز زودتر است، withIslamicOffset() همهٔ تعطیلات اسلامیِ تخمینی را جابه‌جا می‌کند. عدد بین ‎-۳ و ۳ است. فقط روی سال‌های تخمینی اثر دارد. سال‌های رسمی و تعطیلات ثابت دست نمی‌خورند.

PHP
$later = $cal->withIslamicOffset(1);

echo implode(' | ', $cal->getTitles(1406, 12, 7)), "\n";     // عید فطر
echo implode(' | ', $later->getTitles(1406, 12, 7)), "\n";   // (خالی)
echo implode(' | ', $later->getTitles(1406, 12, 8)), "\n";   // عید فطر

echo implode(' | ', $later->getTitles(1405, 1, 1)), "\n";   // جشن نوروز | عید فطر  (سال رسمی تغییر نمی‌کند)

۲. شروع واقعی یک ماه قمری

وقتی هلال دیده شد و روز اول ماه معلوم شد، همان را بدهید. withHijriMonthStart($hijriYear, $hijriMonth, $firstDay) روز اول ماه را به میلادی می‌گیرد (رشته، با رقم فارسی هم قبول است، یا هر DateTimeInterface). همهٔ تعطیلات اسلامی آن ماه از همین روز حساب می‌شوند، حتی در سال‌های رسمی. این تغییر از جدول رسمی و از جابه‌جایی کلی قوی‌تر است.

PHP
// اول شوال ۱۴۴۹ طبق تخمین 2028-02-26 است. هلال یک روز دیرتر دیده شد.
$fixed = $cal->withHijriMonthStart(1449, 10, '2028-02-27');

echo implode(' | ', $fixed->getTitles(1406, 12, 7)), "\n";   // (خالی)
echo implode(' | ', $fixed->getTitles(1406, 12, 8)), "\n";   // عید فطر
echo implode(' | ', $fixed->getTitles(1406, 12, 9)), "\n";   // تعطیل عید فطر

چند قاعده برای تاریخی که می‌دهید:

  • حداکثر ۳ روز با تاریخ محاسبه‌شده فاصله داشته باشد.
  • اگر شروع ماه قبل یا بعد را هم داده‌اید، فاصله‌اش با آن ۲۹ یا ۳۰ روز باشد.
  • تعطیلی امام رضا (آخر صفر) از شروع ربیع‌الاول همان سال حساب می‌شود، اگر داده باشید. وگرنه از شروع صفر و طول صفر در جدول.

تاریخی که این قاعده‌ها را نداشته باشد InvalidDateException می‌دهد.

۳. افزودن و حذف تعطیلی

withHoliday($date, $title) یک تعطیلی به آن روز اضافه می‌کند. $date یک شیء Jalali است یا رشتهٔ جلالی مثل '1406/02/03' (رقم فارسی هم قبول است). withoutHoliday($date) همهٔ تعطیلی‌های آن روز را برمی‌دارد. اگر عنوان هم بدهید، فقط همان عنوان حذف می‌شود.

PHP
$company = $cal
    ->withHoliday('1406/02/03', 'روز شرکت')
    ->withoutHoliday('1406/01/13');   // روز طبیعت را برمی‌داریم

echo implode(' | ', $company->getTitles(1406, 2, 3)), "\n";     // روز شرکت
var_dump($company->isHoliday(1406, 1, 13));                     // bool(false)

$onlyNowruz = $cal->withoutHoliday('1405/01/01', 'عید فطر');
echo implode(' | ', $onlyNowruz->getTitles(1405, 1, 1)), "\n";  // جشن نوروز

متن عنوان نباید خالی باشد، نباید نویسهٔ کنترلی داشته باشد و حداکثر ۲۰۰ نویسه است.

۴. دیدن منبع هر تعطیلی

statusOf() برای هر عنوان نشان می‌دهد از کجا آمده است. جواب فهرستی از HolidayEntry است و هر کدام title و origin دارد. origin یکی از HolidayOrigin::Fixed، Official، Reported، Estimated یا User است.

PHP
foreach ($cal->statusOf(1405, 1, 1) as $entry) {
    echo $entry->title, ' ', $entry->origin->name, "\n";
}
// جشن نوروز Fixed
// عید فطر Official

foreach ($fixed->statusOf(1406, 12, 8) as $entry) {
    echo $entry->title, ' ', $entry->origin->name, "\n";
}
// عید فطر User

با این می‌توانید در رابط کاربری کنار تاریخ‌های تخمینی یک توضیح بگذارید.

جدول گزینه‌ها

این‌ها همان گزینه‌هایی هستند که HolidayCalendar::fromArray() و فایل تنظیمات Laravel (کلید holidays) می‌پذیرند. کلید ناشناخته یا مقدار نادرست InvalidDateException می‌دهد.

گزینهمتد معادلمقدارپیش‌فرض
islamic_offsetwithIslamicOffset()عدد صحیح ‎-۳ تا ۳. فقط سال‌های تخمینی0
hijri_month_startswithHijriMonthStart()نقشه از '1449-10' به تاریخ میلادی روز اول ماه[]
extrawithHoliday()نقشه از تاریخ جلالی به عنوان یا فهرست عنوان‌ها[]
removedwithoutHoliday()تاریخ (همهٔ آن روز) یا نقشه از تاریخ به عنوان یا فهرست عنوان‌ها[]
use_official_datawithOfficialData()true یا falsetrue
PHP
$custom = HolidayCalendar::fromArray([
    'islamic_offset'     => 1,
    'hijri_month_starts' => ['1449-10' => '2028-02-27'],
    'extra'              => ['1406/02/03' => 'روز شرکت'],
    'removed'            => ['1406/01/13'],
]);

echo implode(' | ', $custom->getTitles(1406, 2, 3)), "\n";   // روز شرکت
var_dump($custom->isHoliday(1406, 1, 13));                   // bool(false)

کدام تاریخ برنده است

برای هر روز، این ترتیب اجرا می‌شود:

  1. تغییرهای شما: withHoliday ، withoutHoliday و withHijriMonthStart .
  2. جدول رسمی برای سال‌هایی که دارد.
  3. تخمین از جدول ام‌القری، با withIslamicOffset جابه‌جا می‌شود.

تعطیلات ثابت شمسی (نوروز، ۲۲ بهمن و ...) دقیق‌اند و هیچ جابه‌جایی یا شروع ماهی آن‌ها را عوض نمی‌کند. فقط خودتان با withoutHoliday می‌توانید حذفشان کنید.

در Laravel

فایل تنظیمات را منتشر کنید:

Bash
php artisan vendor:publish --tag=rtly-kit-config

فایل config/rtly-kit.php ساخته می‌شود و گزینه‌ها زیر کلید holidays هستند:

PHP
// config/rtly-kit.php
return [
    'holidays' => [
        'islamic_offset'     => 0,
        'hijri_month_starts' => [],     // '1449-10' => '2028-02-27'
        'extra'              => [],     // '1406/02/03' => 'روز شرکت'
        'removed'            => [],     // '1406/01/13'
        'use_official_data'  => true,
    ],
];

service provider یک HolidayCalendar از این تنظیمات می‌سازد و در container می‌گذارد. کلید جاافتاده مقدار پیش‌فرضش را می‌گیرد. اگر تنظیمات نادرست باشد، خطا موقع اولین استفاده از تقویم پیش می‌آید.

PHP
use RtlyKit\Holiday\HolidayCalendar;

$calendar = app(HolidayCalendar::class);
$calendar->isHoliday(1406, 2, 3);

خوب است بدانید. تابع is_iran_holiday() و متدهای استاتیک IranHolidays همیشه تقویم پیش‌فرض را می‌خوانند، نه تقویمی را که از تنظیمات Laravel ساخته شده. اگر می‌خواهید تنظیمات شما اعمال شود، تقویم را از container بگیرید.

چه چیزی نسبت به نسخه‌های قبل عوض شد

در سال‌های ۱۳۸۰ تا ۱۴۰۵ نتیجه‌ها حالا از تاریخ‌های رسمی یا گزارش‌شده می‌آیند. مثلاً عید فطر ۱۴۴۷ روی ۱۴۰۵/۰۱/۰۱ است. بیرون از این سال‌ها خروجی همان است که قبلاً بود.

برای برگشتن به رفتار قبلی، withOfficialData(false) جدول رسمی را کنار می‌گذارد و همهٔ سال‌ها را تخمین می‌زند. رفتار نسخه‌های قبل از این امکان همین بود.

PHP
$estimate = $cal->withOfficialData(false);

echo $estimate->sourceOf(1405)->name, "\n";                               // Estimated
echo implode(' | ', $estimate->getTitles(1404, 12, 29)), "\n";           // ملی شدن صنعت نفت | عید فطر
echo implode(' | ', $cal->getTitles(1404, 12, 29)), "\n";                // ملی شدن صنعت نفت

نکته‌ها و محدودیت‌ها

  • جابه‌جایی یکنواخت ( withIslamicOffset ) برای ماه‌به‌ماه تفاوت رؤیت هلال کافی نیست. این فقط یک تأخیر ثابت را درست می‌کند. برای تاریخ دقیق یک ماه، withHijriMonthStart را بزنید.
  • برای سال ۱۴۰۶ هنوز تاریخ رسمی منتشر نشده است (تا 2026-10-08). هر وقت منتشر شود به داده اضافه می‌شود و کد شما تغییر نمی‌کند.
  • در سال‌های Reported (۱۳۸۰ تا ۱۳۹۳ و ۱۳۹۵) فقط تاریخ‌ها از یک منبع است و بعضی مناسبت‌ها در فهرست نیستند، مثلاً تعطیلی امام رضا. اگر لازم دارید، با sourceOf() بفهمید و خودتان با withHoliday() اضافه کنید.
  • تعطیلی‌های موردی که دولت اعلام می‌کند (مثل آلودگی هوا) جزو داده نیست. با withHoliday() اضافه‌اش کنید.

مرتبط: تعطیلات، راه‌اندازی Laravel و دقت و داده.