I'm currently working on a project (membership system) with a start date and expiration date. For example the user chose the 30 days membership and his starting date is Sep, 05,2022. So 09/05/2022 30 days is equals to expiration date. But I want to skip sundays when adding the 30 days in the starting date. How can I do that in PHP?
CodePudding user response:
I would use a loop. It's also a great start if you're going to extend that to holidays. Otherwise, it is an overkill but I really don't think you'd suffer performance issues.
So here we go:
$start_date = "2022-09-05";
$start = new DateTime($start_date);
$days = 30;
while ($days) {
// P1D means a period of 1 day
$start->add(new DateInterval('P1D'));
$day = $start->format('N');
// 7 = sunday
if ($day != 7) {
$days--;
}
}
print_r($start);
// output:
// [date] => 2022-10-10 00:00:00.000000
CodePudding user response:
Full weeks should be pre-calculated for better performance. The following function allows you to name one or more days of the week that are not counted.
/**
* Add days without specific days of the week
*
* @param DateTime $startDate start Date
* @param int $days number of days
* @param array $withoutDays array with elements "Mon", "Tue", "Wed", "Thu", "Fri", "Sat","Sun"
* @return DateTime
*/
function addDaysWithout(DateTime $startDate ,int $days, array $withoutDays = []) : DateTime
{
//validate $withoutDays
$validWeekDays = 7 - count($withoutDays);
$validIdentifiers = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat","Sun"];
if($validWeekDays <= 0 OR
$withoutDays != array_intersect($withoutDays,$validIdentifiers)){
$msg = 'Invalid Argument "'.implode(',',$withoutDays).'" in withoutDays';
throw new \InvalidArgumentException($msg);
}
$start = clone $startDate;
$fullWeeks = (int)($days/$validWeekDays)-1;
if($fullWeeks > 0){
$start ->modify($fullWeeks.' weeks');
$days -= $fullWeeks * $validWeekDays;
}
while($days){
$start->modify(' 1 Day');
if(!in_array($start->format('D'),$withoutDays)){
--$days;
}
}
return $start;
}
Application examples:
$start = date_create('2022-09-05');
$dt = addDaysWithout($start,30,["Sun"]);
var_dump($dt);
//object(DateTime)#3 (3) { ["date"]=> string(26) "2022-10-10 00:00:00.000000"
$start = date_create('2022-09-05');
$dt = addDaysWithout($start,30,["Mon","Sun"]);
var_dump($dt);
//object(DateTime)#3 (3) { ["date"]=> string(26) "2022-10-15
Demo: https://3v4l.org/AZX0E