PHP Carbon计算工作日的日期差异

8
我想要以人性化的方式获取两个日期之间的工作日差异。这是我的实际代码:
$start = '2018-09-13 09:30:00';
$end = '2018-10-16 16:30:00';

$from = Carbon::parse($start);
$to = Carbon::parse($end);

$weekDay = $from->diffInWeekdays($to);
$human = $to->diffForHumans($from, true, false, 6);

var_dump($weekDay); //24
var_dump($human); // 1 month 3 days 7 hours

diffForHumans非常适合我的需求,但我找不到任何过滤器,比如diffInDaysFiltered

我想要实现的是获得这个结果:24天7小时,因为我们只有24个工作日

我尝试了先用preg_replace替换3天为$weekDay的结果,但如果在之前有一个月份,它就是不正确的,我得到的是:1个月24天7小时

有没有解决我的问题的方法?


如果您只是单独比较日期的时间部分并将其添加到diffInWeekdays中,会怎样呢? - chiliNUT
@chiliNUT 这是我手动构建的第一个猜测,但如果我遇到“月份”问题,我仍然会遇到相同的问题。 - Baptiste
3个回答

12

感谢imbrish提供的答案。

我需要使用级联因子来定义:

  • 一天有多少小时
  • 一周有多少天
  • 一个月有多少天

然后使用diffFiltered,我可以只选择工作日和工作时间。您还可以通过macro在公共假期上添加过滤器。

CarbonInterval::setCascadeFactors(array(
    'days' => array(10, 'hours'),
    'weeks' => array(5, 'days'),
    'months' => array(20, 'days'),
));

$resolution = CarbonInterval::hour();

$start = Carbon::parse('2017-07-13 11:00');
$end = Carbon::parse('2017-07-17 18:00');

$hours = $start->diffFiltered($resolution, function ($date) {
    return $date->isWeekday() && $date->hour >= 8 && $date->hour < 18;
}, $end);

$interval = CarbonInterval::hours($hours)->cascade();

echo $interval->forHumans(); // 2 days 7 hours

这是 部分:

Carbon::macro('isHoliday', function ($self = null) {
    // compatibility chunk
    if (!isset($self) && isset($this)) {
        $self = $this;
    }
    // Put your array of holidays here
    return in_array($self->format('d/m'), [
        '25/12', // Christmas
        '01/01', // New Year
    ]);
});

然后在diffFiltered内部简单地添加&& !$date->isHoliday()


你能详细说明如何使用宏来过滤公共假期吗? - chiliNUT
1
@chiliNUT 我已添加宏部分。 - Baptiste
这真的很酷。我今天之前不知道宏或级联。 - chiliNUT

2
上述答案都是正确的。但是还有其他一些使用碳的方法。
$startDate = Carbon::create(2017, 4, 4);
$endDate = Carbon::create(2017, 4, 18);
$no_of_days = $startDate->diffInDaysFiltered(function(Carbon $date) {
            return !$date->isSunday();
        }, $endDate);

Carbon 的一些有用函数

  $dt->isMonday();
  $dt->isTuesday();
  $dt->isWednesday();
 $dt->isThursday();
 $dt->isFriday();
 $dt->isSaturday();
 $dt->isSunday();
 $dt->isDayOfWeek(Carbon::SATURDAY); // is a saturday

更多信息请访问https://carbon.nesbot.com/docs/


0

好的,这个解决方案可行,但是在更复杂的时间计算中我遇到了一些问题,所以我想出了另一个使用 while 循环的解决方案。


    Carbon::macro('isHoliday', function ($self = null) {
            // compatibility chunk
            if (!isset($self) && isset($this)) {
                $self = $this;
            }
            // Put your array of holidays here
            return in_array($self->format('d/m'), [
                '23/12', 
                '24/12', 
                '25/12', 
                '26/12', 
                '27/12', 
                '28/12', 
                '29/12', 
                '30/12', 
                '31/12', 
                '01/01', 
                '02/01', 
                '03/01', 
                '04/01', 
                '05/01', 
                '06/01', 
                '07/01', 
            ]);
        });


        $end = Carbon::now();

$hours = 160;
while($hours > 0) {
    if ($end->hour < 9 || $end->hour >= 18 || $end->hour == 13 || $end->isWeekend() || $end->isHoliday()) {
        $end->addHour();
    } else {
        $end->addHour();
        $hours--;
    }
}

        Debugbar::addMessage($end);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接