如何通过一次减去一天找到最近的非假日非周末日期?

时间:2018-03-06 10:28:09

标签: php date oop recursion decrement

我有以下对象数组:

$holiday_calendar = Array
(
    [0] => stdClass Object
        (
            [holiday] => New Year\'s Day
            [holidayDate] => 2018-01-01
        )

    [1] => stdClass Object
        (
            [holiday] => Republic Day
            [holidayDate] => 2018-01-26
        )

    [2] => stdClass Object
        (
            [holiday] => Holi
            [holidayDate] => 2018-03-02
        )
)

$payroll_days_list = Array
(
    [0] => stdClass Object
        (
            [payrollDay] => Mon
            [isPayrollDay] => Y
        )

    [1] => stdClass Object
        (
            [payrollDay] => Tue
            [isPayrollDay] => Y
        )

    [2] => stdClass Object
        (
            [payrollDay] => Wed
            [isPayrollDay] => Y
        )

    [3] => stdClass Object
        (
            [payrollDay] => Thu
            [isPayrollDay] => Y
        )

    [4] => stdClass Object
        (
            [payrollDay] => Fri
            [isPayrollDay] => Y
        )

    [5] => stdClass Object
        (
            [payrollDay] => Sat
            [isPayrollDay] => N
        )

    [6] => stdClass Object
        (
            [payrollDay] => Sun
            [isPayrollDay] => N
        )

)

我需要检查给定的日期是不是假日,不是周六或周日。

如果日期是假日或星期六或星期日,则该日期应该一次一天地移回,直到它符合资格日期。

我写了这段代码:

$dt = "04/03/2018";

echo $dt = $this->checkHolidayExists($dt, $holiday_calendar, $payroll_days_list);

function checkHolidayExists($dt, $holiday_calendar, $payroll_days_list) {
    if (empty($holiday_calendar) && empty($payroll_days_list)) {
        return $dt;
    } else {
        foreach ($holiday_calendar as $hc) {
            if ($hc->holidayDate == $dt) {
                $dt = date('Y-m-d', strtotime($dt . ' -1 days'));
                $this->checkHolidayExists($dt, $holiday_calendar, $payroll_days_list);
            }
        }

        foreach ($payroll_days_list as $pdl) {
            if ($pdl->payrollDay == date('D', strtotime($dt)) && $pdl->isPayrollDay == 'N') {
                $dt = date('Y-m-d', strtotime($dt . ' -1 days'));
                $this->checkHolidayExists($dt, $holiday_calendar, $payroll_days_list);
            }
        }
        return $dt;
    }
}

但是这会返回03/03/2018的日期。

它应该是01/03/2018,因为第4个是星期日,第3个是星期六,第2个是假日。

请让我知道我错过了什么。

1 个答案:

答案 0 :(得分:0)

我必须填写一些缺少的组件,但也许你可以从重写中收集必要的逻辑。我的课程通过颠倒不合格对象数组的顺序来尽量减少递归。

代码:(Demo

class PayDay
{
    public function __construct($Ymd = null) {
        $this->date = $Ymd ?: date("Y-m-d");

        $this->holiday_calendar = [
            (object)["holiday" => "New Year's Day", "holidayDate" => "2018-01-01"],
            (object)["holiday" => "Republic Day", "holidayDate" => "2018-01-26"],
            (object)["holiday" => "Holi", "holidayDate" => "2018-03-02"]
        ];

        $this->payroll_days_list = [
            (object)["payrollDay" => "Mon", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Tue", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Wed", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Thu", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Fri", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Sat", "isPayrollDay" => "N"],
            (object)["payrollDay" => "Sun", "isPayrollDay" => "N"]
        ];

        echo "Starting Date: ",$this->date,"\n";
    }

    public function getPayDate() {
        $hc_match = false;
        foreach (array_reverse($this->holiday_calendar) as $hc) {  // work in reverse to reduce recursions
            if ($hc->holidayDate == $this->date) {
                $hc_match = true;
                //echo "Avoided: ", $hc->holiday,"\n";
                $this->loseOneDay();
                //echo "New Date: ", $this->date,"\n";
            } elseif ($hc_match) {                            // break when consecutive adjustments cease, to reduce recursions
                break;
            }
        }

        $pdl_match = false;
        foreach (array_reverse($this->payroll_days_list) as $pdl) {  // work in reverse to reduce recursions
            if ($pdl->payrollDay == date("D", strtotime($this->date)) && $pdl->isPayrollDay == "N") {
                $pdl_match = true;
                //echo "Avoided: ", $pdl->payrollDay,"\n";
                $this->loseOneDay();
                //echo "New Date: ", $this->date,"\n";
            } elseif ($pdl_match) {                           // break when consecutive adjustments cease, to reduce recursions
                break;
            }
        }

        if ($hc_match || $pdl_match) {
            //echo "\tRECURSE\n";
            $this->getPayDate();
        }
        return $this->date;
    }

    public function loseOneDay(){
        return $this->date = date("Y-m-d", strtotime($this->date." -1 day"));
    }
}

$date = new PayDay("2018-03-04");
echo "Adjusted Date: ", $date->getPayDate();

输出:

Starting Date: 2018-03-04
Adjusted Date: 2018-03-01

请务必使您的日期格式保持一致,以免04/03/20182018-03-04进行比较。当然,格式取决于您,只需为$dt$this->holiday_calendar->holidayDate选择一种格式。

至于您发布的代码,因为您的foreach()循环并未包含break,所以您在找到匹配项后会进行额外/不必要的迭代。

我建议反向迭代对象数组(或者更好的方法是反向声明它们),这样就可以在同一个函数调用中执行连续调整。

经过一番思考之后,我想我可能会使用DateTime对象并花时间准备不合格数据以简化迭代日期调整过程。以下类根本不使用递归,而是使用双条件循环。 (同样,你如何导入不合格的对象数组取决于你。)

代码:(Demo

class PayDay
{
    public function __construct($dmY = null) {
        $this->date = (is_null($dmY) ? new DateTime("midnight") : DateTime::createFromFormat('!d/m/Y', $dmY));  // ! for midnight

        $holiday_calendar = [                                          // import this data however you wish
            (object)["holiday" => "New Year's Day", "holidayDate" => "2018-01-01"],
            (object)["holiday" => "Republic Day", "holidayDate" => "2018-01-26"],
            (object)["holiday" => "Holi", "holidayDate" => "2018-03-02"]
        ];
        $this->blacklist_holidates = [];
        if (!empty($holiday_calendar)) {
            foreach ($holiday_calendar as $obj) {
                $this->blacklist_holidates[$obj->holiday] = DateTime::createFromFormat('!Y-m-d', $obj->holidayDate);  // ! for midnight
            }
        }

        $payroll_days_list = [                                          // import this data however you wish
            (object)["payrollDay" => "Mon", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Tue", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Wed", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Thu", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Fri", "isPayrollDay" => "Y"],
            (object)["payrollDay" => "Sat", "isPayrollDay" => "N"],
            (object)["payrollDay" => "Sun", "isPayrollDay" => "N"]
        ];
        $this->blacklist_daynames = [];
        if (!empty($payroll_days_list)) {
            foreach ($payroll_days_list as $obj) {
                if ($obj->isPayrollDay == "N") {
                    $this->blacklist_daynames[] = $obj->payrollDay;
                }
            }
        }
    }

    public function getPayDate() {
        while (in_array($this->date, $this->blacklist_holidates) || in_array($this->date->format("D"), $this->blacklist_daynames)) {
            $this->date->sub(new DateInterval('P1D'));
        }
        return $this->date->format("d/m/Y");
    }
}

$input = "04/03/2018";
echo "Starting Date: $input\n";
$date = new PayDay($input);
echo "Qualifying PayDate: ",$date->getPayDate();