如何通过一次减去一天来找到最近的非假日、非周末日期?
How to find nearest non-holiday, non-weekend date by subtracting one day at a time?
我有这样的对象数组:
$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;
}
}
但是这个 returns 日期是 03/03/2018
。
应该是01/03/2018
因为4号是周日,3号是周六,2号是节假日
请让我知道我遗漏了什么。
我不得不填写一些缺失的组件,但也许您可以从我的 re-write 中收集必要的逻辑。我的 class 努力通过颠倒取消资格的对象数组的顺序来最大程度地减少递归。
代码:(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/2018
与 2018-03-04
进行比较。当然,格式由你决定,为简单起见,$dt
和$this->holiday_calendar->holidayDate
选择一个即可。
至于您发布的代码,因为您的 foreach()
循环不包含 break
,您在找到匹配后进行 extra/unnecessary 迭代。
我建议反向迭代对象数组(或者更好的是反向声明它们),以便您可以在同一个函数调用中执行连续调整。
再三考虑后,我想我可能会使用 DateTime 对象并花时间准备不合格的数据以简化迭代日期调整过程。下面的class根本就没有使用递归,而是一个dual-condition循环。 (同样,如何导入取消资格的对象数组取决于您。)
代码:(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();
我有这样的对象数组:
$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;
}
}
但是这个 returns 日期是 03/03/2018
。
应该是01/03/2018
因为4号是周日,3号是周六,2号是节假日
请让我知道我遗漏了什么。
我不得不填写一些缺失的组件,但也许您可以从我的 re-write 中收集必要的逻辑。我的 class 努力通过颠倒取消资格的对象数组的顺序来最大程度地减少递归。
代码:(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/2018
与 2018-03-04
进行比较。当然,格式由你决定,为简单起见,$dt
和$this->holiday_calendar->holidayDate
选择一个即可。
至于您发布的代码,因为您的 foreach()
循环不包含 break
,您在找到匹配后进行 extra/unnecessary 迭代。
我建议反向迭代对象数组(或者更好的是反向声明它们),以便您可以在同一个函数调用中执行连续调整。
再三考虑后,我想我可能会使用 DateTime 对象并花时间准备不合格的数据以简化迭代日期调整过程。下面的class根本就没有使用递归,而是一个dual-condition循环。 (同样,如何导入取消资格的对象数组取决于您。)
代码:(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();