Getting the dates of specific days

After careful seeing the code and taking into consideration I conclude in this:

$closedDates = array_map(function ($date) {
    return $date->format('l Y-m-d');
}, $dates);

Some adjustments must be made though…I must add some members to this array.
I must get back an array like this…
array("title"=>"closed","day"=>"saturday","date"=>$date->format('l Y-m-d') ,"time"=> "12:30:00");
The app I am working on deals with arrays like the above…so I must add 3 more members to it…

I have not found a way to do it with array_map. or array_push…I have tried various syntax without success.

Just construct an associate array inside the callback function given to array_map.

$closedDates = array_map(function ($date) {
    return [
        'title' => 'Closed',
        'day' => $date->format('l'),
        'date' => $date->format('l Y-m-d'),
        'time' => '12:30:00'
    ];
}, $dates);

The example above hard codes the time to be 12:30:00 which may not be what you want if different days have different closing times. For example Sundays closed at 13:30:00. A quick example below show one possible way of solving it.

function lookupCloseTime($day)
{
    switch ($day) {
        case 'Saturday':
            return '12:30:00';
        case 'Sunday':
            return '13:30:00';
        default:
            return '14:30:00';
    }
}

$closedDates = array_map(function ($date) {
    $day = $date->format('l');

    return [
        'title' => 'Closed',
        'day' => $day,
        'date' => $date->format('l Y-m-d'),
        'time' => lookupCloseTime($day)
    ];
}, $dates);

I have already tries this and the problem with it is that it produces a multi-dimensional array…something I do not want.

array(4) {
  ["title"]=>
  string(14) "closed"
  ["day"]=>
  string(8) "Tuesday"
  ["date"]=>
  string(10) 2016-03-01"
  ["time"]=>
  string(8) "12:30:00"
}
array(1) {
  [1]=>
  array(4) {
    ["title"]=>
    string(6) "Closed"
    ["day"]=>
    string(7) "Tuesday"
    ["date"]=>
    string(18) "2016-03-01"
    ["time"]=>
    string(8) "12:30:00"
  }
}

Ι want the array to be like the first one above…ΝΟΤ the second one…
The code you gave me returns the second array…which is multi-dimensional.

Sorry you are just confusing me now. $dates is an array that contains 1 or more DateTime objects. array_map is always going to return an array with the same number of items as $dates. What do you get if you print_r($dates)` in my last example?

$dateRange = dateRange(date('Y-m-d'), '2016-03-06');//just an example date range

$dates=array_filter($dateRange, dateFilter(['Tuesday']));//get the tuesdays within the above time segment



$closedDates = array_map(function ($date) {
     return ['title' => 'Closed', 'day' => $date->format('l'),'date' => $date->format('l Y-m-d'),'time' => '12:30:00'];
}, $dates);

var_dump($dates);
//what var_dump prints...I did not use print_r...just for my own convenience
array(1) {
  [1]=>
  object(DateTime)#7 (3) {
    ["date"]=>
    string(19) "2016-03-01 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Athens"
  }
}

I think this is what you asked for.

At the moment your example will only contain a single item in the $dates array as there is only one Tuesday between today and the 6th March. In that case don’t bother with array_map. There are two ways to get what you want. Choose which ever you are happy with. Note that both these examples will only work if $dates contains a single item. They won’t work with more than one date.

The first example uses array_reduce

$dateRange = dateRange(date('Y-m-d'), '2016-03-06');
$dates = array_filter($dateRange, dateFilter(['Tuesday']));
$closed = array_reduce($dates, function ($carry, $date) {
    $carry = [
        'title' => 'Closed',
        'day' => $date->format('l'),
        'date' => $date->format('l Y-m-d'),
        'time' => '12:30:00'
    ];

    return $carry;
}, []);

print_r($closed);

/**
Array
(
    [title] => Closed
    [day] => Tuesday
    [date] => Tuesday 2016-03-01
    [time] => 12:30:00
)
 */

The second just uses the fact that $dates contains a single item.

$dateRange = dateRange(date('Y-m-d'), '2016-03-06');
$dates = array_filter($dateRange, dateFilter(['Tuesday']));
/**
 * This is no longer an option as we need to remove the holes in the array keys
 * so that we can do $dates[0].
 */
$dates = array_values($dates);
$closed = [
    'title' => 'Closed',
    'day' => $dates[0]->format('l'),
    'date' => $dates[0]->format('l Y-m-d'),
    'time' => '12:30:00'
];

print_r($closed);

/**
Array
(
    [title] => Closed
    [day] => Tuesday
    [date] => Tuesday 2016-03-01
    [time] => 12:30:00
)
 */

If $dates contains multiple items then you are going to have to use my earlier examples with array_map

$dates will definitely contain multiple items…so I will use array_map.

But so far using array_map does not return the array in the form I want it.

The problem remains…unless I missed something.

@designtrooper

Did you try the updated version 003?

yes your code does the job…the only thing is that I am trying to figure out how to manipulate $format with in the function such as $result gives this back:

$closed_day=array("title"=>"closed","day"=>"saturday","date"=> "2016-02-27","time"=> "12:30:00")

if we are dealing with one day for example…your code now gives me back this(var_dump):
array(1) { [0]=> string(16) "2016 Mar Thu 3rd"}

I must modify the above so that I get:
$closed_day=array("title"=>"closed","day"=>"Thursday","date"=> "2016-03-09","time"=> "12:30:00")

you are right…I just thought it of again.

Try this:

function fred($val, $title=NULL)
{
  echo '<pre>';
  echo $title ? '<b>'.$title .' == </b>' : NULL;
  print_r($val);
  echo '</pre>';
}


/* =========================================
 function: find the aDays in the time period
 usage:
   getDays($start, $duration, $aDays) 
 where:  
   $start = 'YYYY';   
   $iDays =  365;  // maximum  
   $aDays = ['Mon', 'Wed', 'Fri']; # 3xchar  
========================================= */
function getDays(
    $start  ='2016-12-25', 
    $iDays  = 365, 
    $aDays  = ['Sun', 'Wed', 'Sat'],
    $format = 'D, M jS Y'
) 
{
  $result = [];
  $dStart = date('d', strtotime($start));
  $YM     = substr($start, 0, 8);

  for($i=$dStart; $i<=$iDays; $i++)
  {
    $ok   = strtotime($YM.$i);
    if($ok)
    {
      $date = date('D', $ok);
      foreach($aDays as $day)
      {
        $date = strtolower($date);         
        $day  = strtolower($day);         
        if( $date===$day )
        {
          $result[] = date($format, $ok);
        }
      }//foreach 
    }//$ok
  }

  return $result;
}//endfunc

/* =========================================
 function: addToArray($newDays=arrray())
 usage:
   addToArray($newDay); 
 returns:  
    [title] => closed
    [day]   => Thursday
    [date]  => 2016-03-09
    [time]  => 12:30:00
==========================================*/       
function addToArray($newDays=array())
{
  $result =
  [
    'title' => 'closed', 
    'day'   => 'thursday', 
    'date'  => $newDays[0], 
    'time'  => '12:30'
  ];

  return $result;
}

echo '<b>Parameters:</b>';
  echo '<br>$start  = '; echo $start   = '2016-02-21'; 
  echo '<br>$iDays  = '; echo $iDays   = 365; 
  echo '<br>$aDays  = '; $aDays = ['Sat']; echo "['Sat']";
  echo '<br>$format = '; echo $format  = '"Y-m-d D"';

  echo '<br><br>$newDays = getDays($start, $iDays, $aDays, "Y-m-d D")';

$newDays = getDays($start, $iDays, $aDays, 'Y-m-d D');
fred($newDays, '$newDays');

echo '<br>$newDays = addToArray($newDays)';
$newDays = addToArray($newDays);
fred($newDays, '$newDays');

Output:

I manage to solve my problem with this(see the line where I placed the comment:solution):
function getDays($start , $iDays, $aDays,$format_d,$format_date,$result)
{
$dStart = date(‘d’, strtotime($start));
$YM = substr($start, 0, 8);

  for($i=$dStart; $i<=$iDays; $i++)
  {
    $ok   = strtotime($YM.$i);
    if($ok)
    {
      $date = date('l', $ok);
      foreach($aDays as $day)
      {
        $date = strtolower($date);         
        $day  = strtolower($day);         
        if( $date===$day )
        {
          if(is_array($result) )
          {
             $result[]=array("title"=>"closed","day"=>date($format_d, $ok),"date"=> date($format_date, $ok),"time"=> "12:30:00");//solution
          }else{
            echo '<br>' .date($format_date, $ok);
          }
        }
      }//foreach 
    }//$ok
  }
 return $result;
}

After all…it is OK to have a multi-dimensional array…I just use a foreach loop later.

There is one last thing.
Your code does not work with an end date(you just use a number of days…$idays).
The app I am working deals with an end date in the form of 2016-03-1.

What do you propose?
The only thing I have come up is to make a calculation between startdate and enddata to find how many days separates them and then use this as the value of the $idays variable.

Try this:

//===============================
function debug( $val, $title=NULL )
{
  echo '<pre style="font-family: Courier New">';
    echo $title ? '<b>'.$title .' == </b>' : NULL;
    print_r($val);
  echo '</pre>';
}

//===================================
function newGetDays( $aDefault=NULL )
{
  // Maybe set defaults
    if( ! $aDefault ):
      $aDefault =
      [
        'start'   => '2015-12-20', 
        'end'     => '2016-02-20', 
        'day'     => 'Fri',
        'format'  => 'D, M jS Y', 
        'time'    => '12:30',
      ];
    endif;  

  // set values  
    $aResult = []; 
    $iStart  = strtotime( $aDefault['start'] );
    $iEnd    = strtotime( $aDefault['end']   );
    $iDay    = 24*60*60;

  // loop one day at a time  
    for($i2=$iStart; $i2<=$iEnd; $i2+=$iDay):
      if( $aDefault['day'] == date('D', $i2) ):
        $aResult[] = date( $aDefault['format'], $i2) 
                   . ' &nbsp; &nbsp; '
                   . $aDefault['time'];
      endif;
    endfor;

  return $aResult;
}

//===================================================
// USAGE:
   $result = newGetDays(); // $aDefault
   debug($result, 'Result');

//===================================================

Output

Result == Array
(
[0] => Fri, Dec 25th 2015 12:30
[1] => Fri, Jan 1st 2016 12:30
[2] => Fri, Jan 8th 2016 12:30
[3] => Fri, Jan 15th 2016 12:30
[4] => Fri, Jan 22nd 2016 12:30
[5] => Fri, Jan 29th 2016 12:30
[6] => Fri, Feb 5th 2016 12:30
[7] => Fri, Feb 12th 2016 12:30
[8] => Fri, Feb 19th 2016 12:30
)

array_map will be OK after all… I am OK with a multidimensional array.
There is one last issue though with your code…something I just noticed…more specifically with the date filter function:

function dateFilter(array $daysOfTheWeek)
{
    return function ($date) use ($daysOfTheWeek) {
        return in_array($date->format('l'), $daysOfTheWeek);
    };
}

$closed_dts=array_filter($dateRange, dateFilter(['Saturday'])); //called

The above code works OK…check this below though:

$closed_dts=array_filter($dateRange, dateFilter($closed_days));

…and var_dumping $closed_days give this:
array(2) { [0]=> string(6) "sunday" [1]=> string(8) "saturday"}

…this code does not work…array_filter returns an empty array instead of an array of objects

I cannot understand why this happens…the dateFilter function is supposed to accept an array as an argument…

Its because the values in $closed_days are in lower case. E.g ['sunday', 'saturday']. dateFilter makes a comparison using $date->format('l') which returns the day with a capital letter. I.e Sunday. This causes the comparison to fail as in effect you have ended up with.

// Will return false
in_array('sunday', ['Sunday', 'Saturday']);

When you actually want.

// Will return true
in_array('Sunday', ['Sunday', 'Saturday']);

There are two ways to fix this. The first is to ensure that $closed_days uses capitals when it is passed to dateFilter. If this is not possible and you can only pass lowercase values then you will need to adapt dateFilter to make a comparision using lower case.

function dateFilter(array $daysOfTheWeek)
{
    return function ($date) use ($daysOfTheWeek) {
        return in_array(strtolower($date->format('l')), $daysOfTheWeek);
    };
}

@designtrooper,

I am curious to know how the data is received before it is expanded?

Did you try function newGetDays( $aDefault=NULL )?

Upon reflection the day parameter should have been forced to ucfirst() to prevent any case mis-match.

Do you prefer the array parameter input?

@John_Betong @davidtsadler

Ι want to thank you both…I finally concluded to davidsadler’s code.

1 Like

No problem.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.