'PHP -> Next nearest date defined by array of days in week

please, really need help with this problem.

I have array of offerDays - $offerDays = array(1,6); (mean Monday, and Saturday);

For example, input date is Wednesday 2014/09/03. Next available date for offers is Saturday 2014/09/06

Question: How I can in php determine nearest next day? Something like

$offerDays = array(1,6);
$inputDate = '2014/09/03'; // filled date, not actual date
$offerDate = findDate($inputDate, $offerDays); // returns 2014/09/06

function findDate($inputDate, $offerDays) {
return 'nearest next date to $inputDate defined by $offerDays';
}


Solution 1:[1]

Here you can have a variable array for the offerdays.

$offerDays = array(1,6);
$inputDate = '2014/09/04'; // filled date, not actual date
$offerDate = findDate($inputDate, $offerDays);

function findDate($inputDate, $offerDays) {
   $date = DateTime::createFromFormat('Y/m/d', $inputDate);
   $num = $date->format('w');

   $min = 10; //initialize minimum days
   foreach($offerDays as $o){  //loop through all the offerdays to find the minimum difference
     $dif = $o - $num;
     if($dif>0 && $dif < $min){
        $min = $dif ;
       }
   }
   // if minimum days is not changed then get the first offerday from next week
   if($min == 10){
      $min = 6 - $num + min($offerDays);
   }

   //add the days till next offerday
   $add = new DateInterval('P'.$min.'D');
   $nextOfferDay = $date->add($add)->format('Y/m/d');

  return $nextOfferDay;
}

Solution 2:[2]

$currentDate = date('Y-m-d');
$frequencyDays = [2, 4, 5];

function nextNearestDate($currentDate, $frequencyDays) {
    $weekDay = date('w', strtotime($currentDate));
    $min = 10; // Some random number>7
    foreach ($frequencyDays as $day) {
        $dif = $day - $weekDay;
        if ($dif == 0) {
            $min = $dif;
            break;
        }else if ($dif > 0) {
            $positiveDay[] = $dif;
        }else if ($dif < 0) {
            $negativeDay[] = $dif;
        }
    }
    if ($min != 0) {
        if (isset($positiveDay) && count($positiveDay)) {
            $min = min($positiveDay);
        } else {
            $min = min($negativeDay);
            $min = 7 + $min;
        }
    }
    return $newDay = date('Y-m-d', strtotime('+' . $min . ' days', strtotime($currentDate)));
}

Solution 3:[3]

 $date_str="2014-09-03";
 if(date('l' , $date_str) != 'Saturday')
 {
     //Your Code Here

 }

Solution 4:[4]

Simple Version

<?php

/**
 * Return the next date that falls on one of the specified weekdays.
 *
 * @param  DateTimeInterface $inputDate The search begins on the day after this
 * @param  array             $weekdays  An array of permitted weekdays
 *                                        represented by an integer (0=Sunday)
 *
 * @return DateTimeInterface|null  The first date that meets the criteria
 */
function findDate(DateTimeInterface $inputDate, array $weekdays)
{
    $weekdays = array_flip($weekdays);

    foreach (new DatePeriod($inputDate, new DateInterval('P1D'), 7, DatePeriod::EXCLUDE_START_DATE) as $possibleDate)
    {
        if (isset($weekdays[$possibleDate->format('w')]) === true)
        {
            return $possibleDate;
        }
    }
}

// Example:

$weekdays = [1, 6];
$inputDate = '2014/09/03';

$offerDate = findDate(new DateTimeImmutable($inputDate), $weekdays);

echo $offerDate->format('Y-m-d'), "\n";

Extended Version

If you want to address this by building a slightly more abstract foundation, it may look like:

<?php

function WeekDayIterator(DateTimeInterface $inputDate, array $weekdays)
{
    $weekdays = array_intersect($weekdays, range(0,6));

    if (!$weekdays)
    {
        return;
    }

    $possibleDate = new DateTimeImmutable('@' . $inputDate->getTimeStamp());
    $oneDay = new DateInterval('P1D');
    $weekdays = array_flip($weekdays);

    while (true)
    {
        $possibleDate = $possibleDate->add($oneDay);
        if (isset($weekdays[$possibleDate->format('w')]) === true)
        {
            yield $possibleDate;
        }
    }
}

function findDate(DateTimeInterface $inputDate, array $weekdays)
{
    return WeekDayIterator($inputDate, $weekdays)->current();
}

// Example:

$weekdays = [1, 6];
$inputDate = '2014/09/03';

$offerDate = findDate(new DateTimeImmutable($inputDate), $weekdays);

echo $offerDate->format('Y-m-d'), "\n";

foreach (new LimitIterator(WeekDayIterator(new DateTimeImmutable($inputDate), $weekdays), 0, 10) as $date)
{
    echo $date->format('Y-m-d (w)'), "\n";
}

This longer version gives you an iterator that will infinitely loop over all valid dates. The findDate method now just becomes a convenience method to hide away the implementation details.

But the advantage here is that you can now solve similar problems without having to write more plumbing. For example, you can compute the next 10 dates with a LimitIterator. (Maybe you want to provide a drop down of available dates, etc.)

This second version is heavily dependent on 5.5, but the first version is not (if you replace the DateTimeImmutable with DateTime).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 TeeDeJee
Solution 2
Solution 3 Tristup
Solution 4