Към съдържанието
PN Scripts

Разработка

Работни и почивни дни в България: как автоматизациите да ги смятат вярно

  • PN Scripts
  • 8 мин четене

Рано или късно всяка бизнес система трябва да знае дали дадена дата е работен ден. За заплатите са нужни работните дни и часове в месеца. Куриерът обещава „доставка до 2 работни дни“. Автоматичният отговор на офиса, напомнянето, срокът „до 14 работни дни“ и дори будилникът в умния дом зависят от същия въпрос. В България отговорът не е „от понеделник до петък минус един постоянен списък“: Великден се мести по православния календар, празниците през уикенда отиват на следващия работен ден, а правителството понякога обявява допълнителни почивни дни. Тук събираме правилата, даваме тестван PHP код и показваме къде обикновено се чупи ръчно писаният код.

#Официалните празници

Чл. 154, ал. 1 от Кодекса на труда изброява официалните празници:

  • 1 януари, Нова година;
  • 3 март, Ден на Освобождението на България от османско иго, националният празник;
  • 1 май, Ден на труда и на международната работническа солидарност;
  • 6 май, Гергьовден, Ден на храбростта и Българската армия;
  • 24 май, Ден на светите братя Кирил и Методий, на българската азбука, просвета и култура и на славянската книжовност;
  • 6 септември, Ден на Съединението;
  • 22 септември, Ден на Независимостта на България;
  • 24, 25 и 26 декември, Бъдни вечер и Рождество Христово;
  • Разпети петък, Велика събота, Великден (неделя) и понеделник след него, по православния календар.

Същият член назовава и 1 ноември, Деня на народните будители, но само като неприсъствен ден за всички учебни заведения. За всички останали той е работен ден. Само това изключение вече чупи общ списък с почивни дни за офиса и за семейния календар.

#Православният Великден се мести всяка година

Четири от празниците зависят от православния Великден, който се смята по юлианския календар и обикновено е по-късно от католическия. През 2026 г. той е на 12 април, а през 2027 г. на 2 май. Вградената в PHP функция easter_date() дава католическата дата, затова не може да се ползва директно. Алгоритъмът на Меус за юлианския календар, отместен с 13 дни към григорианския, е кратък и точен за годините от 1900 до 2099:

function orthodox_easter(int $year): DateTimeImmutable
{
    $a = $year % 4;
    $b = $year % 7;
    $c = $year % 19;
    $d = (19 * $c + 15) % 30;
    $e = (2 * $a + 4 * $b - $d + 34) % 7;
    $month = intdiv($d + $e + 114, 31);
    $day = ($d + $e + 114) % 31 + 1;

    // Julian calendar date + 13 days = Gregorian date (valid 1900 to 2099).
    return (new DateTimeImmutable(sprintf('%d-%02d-%02d', $year, $month, $day)))->modify('+13 days');
}

#Празник през уикенда се мести на следващия работен ден

Чл. 154, ал. 2 добавя правилото, което повечето код забравя: когато празник, различен от великденските, се падне в събота или неделя, първият работен ден след него е неприсъствен, тоест почивен. Два празника през уикенда дават два такива дни. Няколко примера:

  • 24 май 2026 г. е неделя, затова понеделник, 25 май 2026 г., е почивен.
  • 6 септември 2026 г. е неделя, затова понеделник, 7 септември, е почивен.
  • 26 декември 2026 г. е събота, затова понеделник, 28 декември, е почивен.
  • 25 и 26 декември 2027 г. са събота и неделя, затова понеделник, 27, и вторник, 28 декември 2027 г., са почивни.
  • 1 май 2027 г. се пада на Велика събота, а следващият понеделник вече е Великден, затова допълнителният почивен ден е вторник, 4 май 2027 г. Същото се случи и през 2021 г.

Кодът по-долу първо добавя постоянните празници и великденските дни, а след това мести всеки празник от уикенда на следващия делничен ден, който още не е почивен. Обработката по реда на датите покрива и двойната Коледа, и съвпадението с Великден:

function bulgarian_days_off(int $year): array
{
    $fixed = ['01-01', '03-03', '05-01', '05-06', '05-24', '09-06', '09-22', '12-24', '12-25', '12-26'];
    $off = [];
    foreach ($fixed as $md) {
        $off["$year-$md"] = true;
    }

    $easter = orthodox_easter($year);
    foreach (['-2 days', '-1 day', '+0 days', '+1 day'] as $shift) {
        $off[$easter->modify($shift)->format('Y-m-d')] = true;   // Good Friday to Easter Monday
    }

    // Art. 154(2): a holiday other than Easter on a Saturday or Sunday gives the next free weekday off.
    foreach ($fixed as $md) {
        $date = new DateTimeImmutable("$year-$md");
        if ((int) $date->format('N') < 6) {
            continue;
        }
        do {
            $date = $date->modify('+1 day');
        } while ((int) $date->format('N') >= 6 || isset($off[$date->format('Y-m-d')]));
        $off[$date->format('Y-m-d')] = true;
    }

    ksort($off);

    return array_keys($off);
}

function is_working_day(DateTimeImmutable $date, array $extraDaysOff = []): bool
{
    $day = $date->format('Y-m-d');

    return (int) $date->format('N') < 6
        && ! in_array($day, bulgarian_days_off((int) $date->format('Y')), true)
        && ! in_array($day, $extraDaysOff, true);
}

Сверихме го с публикуваните календари: като преместени почивни дни дава 26 май и 8 септември 2025 г., 25 май, 7 септември и 28 декември 2026 г., както и 4 май, 27 и 28 декември 2027 г. Според него декември 2026 г. има 20 работни дни, а 14 работни дни след петък, 18 декември 2026 г., е сряда, 13 януари 2027 г.

#Дни, които обявява правителството

Министерският съвет може да обяви допълнителни неприсъствени дни. За въвеждането на еврото обяви 31 декември 2025 г. и 2 януари 2026 г. Никоя формула не ги предвижда, затова функцията по-горе приема списък с допълнителни почивни дни. Дръжте този списък в настройките, а не в кода, така че който поддържа системата, да може да добави деня в седмицата, в която е обявен. В същия списък е мястото и на фирмените ви почивни дни.

#Часове в месеца и срокове

Две изчисления има в почти всяка българска бизнес система:

  • Работните часове в месеца: работните дни, умножени по продължителността на работния ден, обикновено 8 часа. Декември 2026 г. дава 20 × 8 = 160 часа. Те трябват за часовата ставка и извънредния труд.
  • Срок в работни дни: вървете напред ден по ден и броете само работните дни, както в примера по-горе. Никога не добавяйте календарни дни, за да „поправите уикендите“ след това; така пропускате празниците по средата на периода.

Пазете входните данни, например списъка с допълнителни почивни дни, до резултата. Когато през март някой попита защо срокът е определен така през януари, ще можете да отговорите.

#Къде обикновено се чупи ръчно писаният код

  • Католически Великден от easter_date() вместо православен.
  • Няма преместени почивни дни или има само един, когато се срещнат два празника през уикенда.
  • Местят се и великденските празници, които Кодексът на труда изключва.
  • 1 ноември е почивен за всички или пък е забравен за училищата.
  • Твърд списък за една година, който никой не обновява през януари.
  • Часови зони: сървър с UTC решава кое е „днес“ два или три часа преди София.

#Същите правила в Home Assistant

Написахме тези правила още веднъж за умни домове и малки офиси, които ползват Home Assistant: Sedmitsa е интеграция, която знае празниците по Кодекса на труда с православния Великден, преместените почивни дни и обявените дни при въвеждането на еврото. Всеки добавен календар дава сензори за работен ден днес и утре, вида на деня, следващия почивен ден с дължината на цялата почивка, следващия работен ден и работните дни и часове в месеца. Календарен обект показва всеки празник. Изберете група класове и получавате и сензори за учебен ден и училищния календар за 2026/2027 г. по заповедта на министъра на образованието. Три действия отговарят на скриптове: проверка на дата, брой работни дни и дата след определен брой работни дни. Собствените почивни дни и работната събота са настройки, а не код.

Работи локално, без облачна услуга и без акаунт. Нейните 132 автоматични теста вървят в Home Assistant Core 2026.10.0, а правилата за празниците са сверени с публикуваните български календари за 2021 до 2027 г. Sedmitsa е обявена като „Очаквайте скоро“.

#Често задавани въпроси

Ако празник се падне в събота, почивен ли е петъкът преди него?

Не. По чл. 154, ал. 2 от Кодекса на труда почивният ден се мести напред, към първия работен ден след празника, обикновено понеделник.

Местят ли се и великденските празници?

Не. Разпети петък, Велика събота, Великден и понеделникът след него са изключени от правилото. Велика събота и Великден никога не дават допълнителен почивен ден.

Почивен ли е 1 ноември?

Не и за работещите по принцип. Кодексът на труда го прави неприсъствен ден само за учебните заведения, затова училищният календар го третира различно от календара на офиса.

Как да се справя с ден, който правителството обяви по-късно?

Пазете списък с допълнителни почивни дни в настройките и добавете деня веднага щом решението бъде обнародвано. Никой алгоритъм не може да ги предвиди.

#Източници

Още по темата

Още по темата

Коментари

Коментари

Напишете първия коментар.

Оставете коментар

Следваща стъпка

pnscripts.com/bg/contact

Пишете на екипа

Попитайте за статия или ни разкажете за проект, който искате да изградим. Отговаряме до един работен ден.

Пишете ни

Семейството PN Scripts

Другите сайтове на PN Scripts

Хостингът, игрите и блогът имат свои сайтове, поддържани от същата компания.

  • pnscripts.com

    PN Scripts

    Софтуерно инженерство

    Уеб и мобилни приложения, API и игри по поръчка, плюс нашите продукти и плъгини с отворен код.

  • games.pnscripts.com

    Игри

    Игри и игрови сървъри

    Домът на игрите на PN Scripts: безплатни браузърни игри, които се играят веднага, а игровите сървъри предстоят.

  • hosting.pnscripts.com

    Хостинг

    Хостинг и инфраструктура

    Споделен хостинг, KVM VPS, самостоятелни сървъри и домейни от същата компания, която изработва проекта ви.

  • blog.pnscripts.com

    Блог

    Статии и бележки

    Практични статии за разработка на софтуер, хостинг, отворен код и игри, писани от хората, които ги създават.

    Вие сте тук