CALCulate трудодни между двумя датами, включая праздники и таможенной рабочей недели
Ответ не так тривиально - таким образом, мое предложение было бы использовать класс, в котором вы можете настроить больше, чем полагаться на упрощенную функцию (или предполагать фиксированный язык и культуру). Для того, чтобы получить дату после определенного количества рабочих дней вы будете:
- необходимо указать, какие дни недели вы будете работать (по умолчанию для MON-FRI) - класс позволяет включить или отключить каждый будний день по отдельности.
- необходимо знать, что вам необходимо учитывать праздничные дни (страна и штат), чтобы быть точным
Функциональный подход
/**
* @param days, int
* @param $format, string: dateformat (if format defined OTHERWISE int: timestamp)
* @param start, int: timestamp (mktime) default: time() //now
* @param $wk, bit[]: flags for each workday (0=SUN, 6=SAT) 1=workday, 0=day off
* @param $holiday, string[]: list of dates, YYYY-MM-DD, MM-DD
*/
function working_days($days, $format='', $start=null, $week=[0,1,1,1,1,1,0], $holiday=[])
{
if(is_null($start)) $start = time();
if($days <= 0) return $start;
if(count($week) != 7) trigger_error('workweek must contain bit-flags for 7 days');
if(array_sum($week) == 0) trigger_error('workweek must contain at least one workday');
$wd = date('w', $start);//0=sun, 6=sat
$time = $start;
while($days)
{
if(
$week[$wd]
&& !in_array(date('Y-m-d', $time), $holiday)
&& !in_array(date('m-d', $time), $holiday)
) --$days; //decrement on workdays
$wd = date('w', $time += 86400); //add one day in seconds
}
$time -= 86400;//include today
return $format ? date($format, $time): $time;
}
//simple usage
$ten_days = working_days(10, 'D F d Y');
echo '<br>ten workingdays (MON-FRI) disregarding holidays: ',$ten_days;
//work on saturdays
$ten_days = working_days(10, 'D F d Y', null, [0,1,1,1,1,1,1]);
echo '<br>ten workingdays (MON-SAT) disregarding holidays: ',$ten_days;
//only work on weekends and specify some days off (e.g. tomorrow)
$ten_days = working_days(10, 'D F d Y', null, [1,0,0,0,0,0,1], ['01-01', date('Y-m-d', time()+86400), '12-25']);
echo '<br>ten workingdays (MON-FRI) excluding tomorrow and specifying with some holidays: ',$ten_days;
OO Подход
// usage after including the WorkingDays class below
// (you can specify holidays, vacation and customize workweeks)
// WorkingDays::$holiday[] = '12-25'; //add Dec 25th as day off
// WorkingDays::$sat = 1; //enable working on Saturday
$date_after_workdays = WorkingDays::fromNow(10);
echo 'after ten working days it will be ', date('D F d Y', $date_after_workdays);
/**
* class to calculate date after certain amount of working days.
* Depending on location and contract "working days" is very relative.
* By default this class is assuming standard western office hours.
*
* @see http://en.wikipedia.org/wiki/Workweek_and_weekend
* @see e.g. http://www.timeanddate.com/holidays/
* @see e.g. http://www.officeholidays.com/
*
* @usage
* WorkingDays::$holiday[] = '12-25'; //add Dec 25th as day off
* WorkingDays::$sat = 1; //enable working on Saturday
* $date_done = date('F d Y', WorkingDays::fromNow(10));
*/
class WorkingDays
{
//workweek definition
public static $mon = 1;
public static $tue = 1;
public static $wed = 1;
public static $thu = 1;
public static $fri = 1;
public static $sat = 0;
public static $sun = 0;
//use format MM-DD to define non-workingdays (holidays, vacation, etc.)
public static $holiday = ['01-01', /* ... */];
/**
* @param $start, int: timestamp (time or mktime)
* @param $days, int: workingdays from date
* @return int: timestamp of date
*/
public static function from($start, $days)
{
if($days <= 0) return $start;
$wk = [self::$sun, self::$mon, self::$tue, self::$wed, self::$thu, self::$fri, self::$sat];
if(array_sum($wk) == 0) trigger_error('workweek must contain at least one workday');
$wd = date('w', $start);//0=sun, 6=sat
$time = $start;
while($days)
{
if($wk[$wd] && !in_array(date('m-d', $time), self::$holiday)) --$days; //decrement on workdays
$wd = date('w', $time += 86400); //add one day in seconds
}
$time -= 86400;//include today
return $time;
}
/**
* "today" is included (if it is a workday)
*/
public static function fromNow($days)
{
return self::from(time(), $days);
}
}
'StrToTime ('п ow ') 'является массово неэффективным. почему не просто 'time()'? –
@MarcB ok, но все остальное код правильный? – dames
выглядит так, как будто он должен работать, но вы, возможно, могли бы сделать это без петли вообще. –