Несколько дней новогоднего волшебства:
Успейте начать обучение в 2018-ом году со скидкой до 30%!
Выбрать курс

Прибавляем два часа рабочего времени на PHP

PHP_Deep_29.06_SITE.png

Представим: за час до конца рабочего дня, 29 декабря 2017 года, вам поручили срочное двухчасовое задание – рассчитать на PHP время его окончания. Казалось бы, что тут сложного? Добавить 2*3600 секунд к текущему времени и всё!

Вот так:

class WorkHours
{
    public function addHours ($date, $hours)
    {
        $time = strtotime ($date); // переводим дату в секунды
        for ($j = 0; $j < $hours; $j ++) // в цикле добавляем по часу
            $time = $this -> addHour ($time);
        return date ("Y-m-d H:i:s", $time); // конвертируем в дату
    }

    function addHour ($time)
    {
        return $time + 3600; // добавляем один час
    }

}

Но в преддверии Нового года не всё так просто...

Для решения задачи нужно учитывать время начала и окончания рабочего дня, обеденный перерыв, а также выходные и праздничные дни. То есть функция addHour () должна добавлять по одному часу до тех пор, пока выпадает нерабочий час, выходной день или праздник.

Начнём с рабочих часов

Будем считать, что фирма работает с 9:00 до 18:00 с перерывом на обед с 13:00 до 14:00. Создадим массив, в котором перечислим все нерабочие часы в течение суток:

    private $offtimes = array (
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // утром
        13,  // обед
        19, 20, 21, 22, 23); // вечером

    function isOfftime ($time)
    {
        return in_array (date ("G", $time),  // час без ведущего нуля
            $this -> offtimes);  // список нерабочих часов
    }

Теперь разберёмся с выходными днями

Составим список и напишем функцию проверки:

    private $weekends = array ("Sat", "Sun");

    function isWeekend ($time)
    {
        return in_array (date ("D", $time), // буквенный код дня недели
            $this -> weekends); // список выходных дней недели
    }

Сложнее всего с праздничными днями

На каждый год для заданной страны их нужно перечислять отдельно, либо подключиться к базе, откуда можно их получать. В рамках этой статьи мы перечислим их прямо в коде:

    private $holydays = array (
        "2018-01-01",  "2018-01-02",  "2018-01-03",
        "2018-01-04",  "2018-01-05",  "2018-01-06",
        "2018-01-07",  "2018-01-08",  "2018-02-23",  );

    function isHolyday ($time)
    {
        return in_array (date ("Y-m-d", $time), // конвертируем в дату
            $this -> holydays); // ищем в списке праздников
    }

Вот теперь можно переписать функцию добавления одного часа

Будем добавлять 3600 секунд, пока выполняются условия: – данный час попадает на выходной день; – данный час выпадает на праздничный день; – данный час является нерабочим.

    function addHour ($time)
    {
        do
            $time += 3600;
        while ($this -> isWeekend ($time) // выходной
            || $this -> isHolyday ($time) // праздник
            || $this -> isOfftime ($time)); // нерабочий час
        return $time;
    }

Проверка часа на выполнение данных условий производится ранее рассмотренными функциями: – isWeekend ($time) – проверка на выходной, – isHolyday ($time) – проверка на праздничный день, – isOfftime ($time) – проверка на нерабочее время.

Теперь мы можем решить поставленную задачу:

<?php
    $wh = new WorkHours ();
    $date_from = "2017-12-29 17:00:00";
    $date_till = $wh -> addHours ($date_from, 2);
    echo $date_from . "\n" . $date_till;
?>
2017-12-29 17:00:00
2018-01-09 10:00:00

У нас ещё есть Время!

Есть вопрос? Напишите в комментариях!

Автор
2 комментария
2

С выходными днями: по-моему проще использовать date ("w", $time) > 5

С рабочими часами: список рабочих часов был бы короче, чем список нерабочих часов

И что за "var"? Это ж пережиток v4

0

Я предпочитаю использовать конструкции, которые понятны всем. Вариант с перечислением дней недели понятен сразу. По поводу списка часов - это единый стиль в классе. Мы перечисляем выходные дни, праздничные дни, соответственно, логично перечислять нерабочие часы.

Для комментирования необходимо авторизоваться