Мне нужно найти три предыдущих рабочих дня с указанной даты, исключая выходные и праздничные дни. Само по себе это не сложная задача, но, похоже, то, как я собирался это сделать, было бы слишком сложным, поэтому я решил сначала спросить ваше мнение.
Чтобы сделать вещи более интересными, давайте сделаем это соревнованием. Я предлагаю 300 в качестве награды тому, кто придумает самое короткое и чистое решение, соответствующее этой спецификации:
- Напишите функцию, которая возвращает три предыдущих рабочих дня с указанной даты
- Рабочий день определяется как любой день, который не является субботой или воскресеньем и не является выходным
- Функция знает выходные дни года указанной даты и может учитывать их
- Функция принимает один параметр - дату в формате
Y-m-d
- Функция возвращает массив с тремя датами в формате
Y-m-d
, отсортированный от самой старой к самой новой.
Дополнительно:
- Функция может также найти следующие три рабочих дня в дополнение к предыдущим трем
Пример массива праздничных дней:
$holidays = array(
'2010-01-01',
'2010-01-06',
'2010-04-02',
'2010-04-04',
'2010-04-05',
'2010-05-01',
'2010-05-13',
'2010-05-23',
'2010-06-26',
'2010-11-06',
'2010-12-06',
'2010-12-25',
'2010-12-26'
);
Обратите внимание, что в реальном сценарии праздники не жестко закодированы, а поступают из функции get_holidays($year)
. Вы можете включить / использовать это в своем ответе, если хотите.
Поскольку я предлагаю вознаграждение, это означает, что пройдет не менее трех дней, прежде чем я смогу пометить ответ как принятый (2 дня, чтобы добавить вознаграждение, 1 день, пока я не смогу принять).
Примечание
Если вы используете фиксированную продолжительность дня, например 86400 секунд, для перехода от дня к другому, у вас возникнут проблемы с переходом на летнее время. Вместо этого используйте strtotime('-1 day', $timestamp)
.
Пример этой проблемы:
http://codepad.org/uSYiIu5w
Окончательное решение
Вот окончательное решение, которое я в итоге использовал, адаптированное из идеи Кейта Минклера об использовании strtotime
last weekday
. Определяет направление по пройденному счету, если оно отрицательное, выполняет поиск в обратном направлении и вперед при положительном:
function working_days($date, $count) {
$working_days = array();
$direction = $count < 0 ? 'last' : 'next';
$holidays = get_holidays(date("Y", strtotime($date)));
while(count($working_days) < abs($count)) {
$date = date("Y-m-d", strtotime("$direction weekday", strtotime($date)));
if(!in_array($date, $holidays)) {
$working_days[] = $date;
}
}
sort($working_days);
return $working_days;
}