How might I code a function in PHP (with CodeIgniter) to merge days with similar opening hours of a store together. For example, if we have:
Mon 9am-5pm
Tue 9am-5pm
Wed 9am-5pm
Thu 9am-5pm
Fri 9am-5pm
Sat 9am-7pm
Sun 9am-7pm
I want the code to simplify it to:
Mon-Fri 9am-5pm
Sat-Sun 9am-7pm
How do I do this without a long list of if/else or case ifs? I'm using CodeIgniter..
<?php
$openHours = array(
'Mon' => '9am-5pm',
'Tue' => '9am-5pm',
'Wed' => '9am-9pm',
'Thu' => '9am-5pm',
'Fri' => '9am-5pm',
'Sat' => '9am-7pm',
'Sun' => '9am-7pm'
);
$summaries = array();
foreach ($openHours as $day => $hours) {
if (count($summaries) === 0) {
$current = false;
} else {
$current = &$summaries[count($summaries) - 1];
}
if ($current === false || $current['hours'] !== $hours) {
$summaries[] = array('hours' => $hours, 'days' => array($day));
} else {
$current['days'][] = $day;
}
}
foreach ($summaries as $summary) {
if (count($summary['days']) === 1) {
echo reset($summary['days']) . ' ' . $summary['hours'] . PHP_EOL;
} else {
echo reset($summary['days']) . '-' . end($summary['days']) . ' ' . $summary['hours'] . PHP_EOL;
}
}
codepad sample
If you want it in the following format:
Sun-Tue, Fri-Sat: 11am-12am; Wed: 10am-12am; Thu: 9am-12am
Which will group days and handle different times within the week:
<?php
$open_hours = array (
"Sun" => "11am-12am",
"Mon" => "11am-12am",
"Tue" => "11am-12am",
"Wed" => "10am-12am",
"Thu" => "9am-12am",
"Fri" => "11am-12am",
"Sat" => "11am-12am"
);
$result = [];
foreach ($open_hours as $day => $hours) {
if (empty($result) || $previous !== $hours) {
$result[$hours][] = $day;
} elseif ($previous === $hours) {
$key = array_key_last($result[$hours]);
$current = strtok($result[$hours][$key], '-');
$result[$hours][$key] = $current.'-'.$day;
}
$previous = $hours;
}
// build output (joining days with ,)
$output = [];
foreach ($result as $hours => $days) {
$output[] = implode(', ', $days).': '.$hours;
}
// join with ;'s and output
echo implode('; ', $output);
https://3v4l.org/tKOlI
Related
I am creating a function where you can give a starting year, month and end year, month and the function will print every month and year in between the two given points.
I've already created a function that works perfectly but I believe this is not a good practice and there might be better way to do this. Now I am seeking your help to find a better way.
P.S. I can't get full date as input. Only can get month number and year.
Here is my code -
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
if (($monthstart === null) || ($yearstart === null) || ($monthend === null) || ($yearend === null)) {
$monthend = date('m');
$yearend = date('Y');
if($monthend < 6) {
$yearstart = $yearend - 1;
$monthstart = (($monthend - 5) + 12);
} else {
$yearstart = $yearend;
$monthstart = $monthend - 5;
}
}
$month_array = array();
if ($yearstart > $yearend) {
for ($m=$monthend; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
for ($y=$yearend+1; $y<$yearstart; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthstart; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
} elseif ($yearend > $yearstart) {
for ($m=$monthstart; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
for ($y=$yearstart+1; $y<$yearend; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
} else {
for ($m=$monthstart; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
}
return $month_array;
}
EDIT: Based on Nigel Ren's answer, this is the best way I could think of -
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
if (($monthstart === null) || ($yearstart === null) || ($monthend === null) || ($yearend === null)) {
$monthend = date('m');
$yearend = date('Y');
if($monthend < 6) {
$yearstart = $yearend - 1;
$monthstart = (($monthend - 5) + 12);
} else {
$yearstart = $yearend;
$monthstart = $monthend - 5;
}
}
$output = [];
if ($yearstart > $yearend) {
$time = strtotime($yearend."-".$monthend);
$last = date('m-Y', strtotime($yearstart."-".$monthstart));
} else {
$time = strtotime($yearstart."-".$monthstart);
$last = date('m-Y', strtotime($yearend."-".$monthend));
}
do {
$cur_month_year = date('m-Y', $time);
$month = date('m', $time);
$year = date('Y', $time);
$output[] = array('month'=>$month,'year'=>$year);
$time = strtotime('+1 month', $time);
}
while ($cur_month_year != $last);
return $output;
}
You can use PHP's DateInterval class which is used for these purposes. Try this code
<?php
function getMonthsFromRange($start, $end, $format = 'M Y')
{
$array = array();
// Since you wanted 1 month it is Period = 1 Month
$interval = new DateInterval('P1M');
$realEnd = new DateTime($end);
$realEnd->add($interval);
$period = new DatePeriod(new DateTime($start), $interval, $realEnd);
// Use loop to store date into array
foreach ($period as $date)
$array[] = $date->format($format);
// Return the array elements
return $array;
}
// Function call with passing the start date and end date
$months = getMonthsFromRange('2010-10', '2011-11');
print_r($months);
It's output is:
Array ( [0] => Oct 2010 [1] => Nov 2010 [2] => Dec 2010 [3] => Jan 2011 [4] => Feb 2011 [5] => Mar 2011 [6] => Apr 2011 [7] => May 2011 [8] => Jun 2011 [9] => Jul 2011 [10] => Aug 2011 [11] => Sep 2011 [12] => Oct 2011 [13] => Nov 2011 )
Based on the answer here, it can be done simply by adding 1 month to the start date till you get to the end date...
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
$output = [];
$time = strtotime($yearstart."-".$monthstart);
$last = date('m-Y', strtotime($yearend."-".$monthend));
do {
$month = date('m-Y', $time);
$output[] = $month;
$time = strtotime('+1 month', $time);
}
while ($month != $last);
return $output;
}
So
print_r(get_all_months(4,2008,2,2010));
gives...
Array
(
[0] => 04-2008
[1] => 05-2008
[2] => 06-2008
[3] => 07-2008
[4] => 08-2008
[5] => 09-2008
[6] => 10-2008
[7] => 11-2008
[8] => 12-2008
[9] => 01-2009
[10] => 02-2009
[11] => 03-2009
[12] => 04-2009
[13] => 05-2009
[14] => 06-2009
[15] => 07-2009
[16] => 08-2009
[17] => 09-2009
[18] => 10-2009
[19] => 11-2009
[20] => 12-2009
[21] => 01-2010
[22] => 02-2010
)
probably you're looking for something like this:
function get_all_months($monthstart = null, $yearstart = null, $monthend = null, $yearend = null) {
$month_array = [];
if ($yearstart == $yearend)
for ($m=$monthstart; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
else {
for ($m=$monthstart; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $yearstart);
for ($y=$yearstart+1; $y<$yearend; $y++) for ($m=1; $m<=12; $m++) $month_array[] = array('month' => $m, 'year' => $y);
for ($m=1; $m<=$monthend; $m++) $month_array[] = array('month' => $m, 'year' => $yearend);
}
return $month_array;
}
If I understand correctly - you get the month as a number and the year as a number e.g 6 and 1997. If we assume that the start year is always less than the end year I would suggest going like this.
function distanceBetweenDates(int $sm, int $sy, int $em, int $ey) {
$monthsBetweenYears = ($ey - $sy + 1) * 12;
$distanceBetweenMonths = $monthsBetweenYears - $sm - (12 - $em);
$startMonth = $sm + 1;
$startYear = $sy;
while ($distanceBetweenMonths > 0) {
if ($startMonth <= 12) {
echo $startMonth . ' - ' . $startYear;
} else {
$startMonth = 1;
$startYear++;
echo $startMonth . ' - ' . $startYear;
}
echo "\n";
$startMonth++;
$distanceBetweenMonths--;
}
}
The only thing you might need to see is if the given months are included or excluded from the calculation.
The only thing missing here is the validation since it can be "skipped" of a sort if you use types inside the method.
With the DateTime class and DateInterval, you can create a generator of DateTime object of the specified range:
<?php
function get_all_months(int $monthstart, int $yearstart, int $monthend, int $yearend) {
$onemonth = new DateInterval('P1M'); // one month interval
$timeperiod = new DatePeriod(
DateTime::createFromFormat('Y-m', "{$yearstart}-{$monthstart}"),
$onemonth,
DateTime::createFromFormat('Y-m', "{$yearend}-{$monthend}")->add($onemonth)
);
foreach ($timeperiod as $pos) {
yield clone $pos;
}
}
foreach (get_all_months(12, 2009, 1, 2020) as $month) {
echo "{$month->format('Y-m')}\n";
}
DateTime should be more flexible to use than plain string or number array (see DateTime::format for more usage options).
Note: inspired by #keidakida, updated my answer.
I have a function to get the Time-ago from a Timestamp, I grabbed it somewhere from the internet and developed and optimized it. It's fully functioning. The problem here is that it ONLY gets time-ago (from a past Timestamp), it didn't process future Timestamps (It returns 0 seconds ago).
Is anybody able to help me add this functionality to the function?
<?php
function time_ago( $ts, $format ) {
// $format = 'l, F d, Y H:i';
$granularity = 1;
$dif = time() - $ts;
if ( $dif < 0 )
return '0 Seconds ago';
elseif ( $dif < 604800 ) { // 604800 7 days / 864000 10 days
$periods = array(
'Week' => 604800,
'Day' => 86400,
'Hour' => 3600,
'Minute' => 60,
'Second' => 1
);
$output = '';
foreach ( $periods as $key => $value ) {
if ( $dif >= $value ) {
$time = round( $dif / $value );
$dif %= $value;
$output .= ( $output ? ' ' : '' ) . $time . ' ';
$output .= ( ( $time > 1 ) ? $key . 's' : $key );
$granularity --;
}
if ( $granularity == 0 )
break;
} // foreach( $periods as $key => $value )
return ($output ? $output : '0 seconds') . ' ago';
} else
return date( $format, $ts );
}
?>
I've edited your function. Now it displays a time in the future as In 10 Hours.
Code:
function time_ago( $ts, $format ) {
// $format = 'l, F d, Y H:i';
$granularity = 1;
$dif = time() - $ts;
$future = $dif < 0 ? true : false;
$dif = abs($dif);
if ( $dif < 604800 ) { // 604800 7 days / 864000 10 days
$periods = array(
'Week' => 604800,
'Day' => 86400,
'Hour' => 3600,
'Minute' => 60,
'Second' => 1
);
$output = '';
foreach ( $periods as $key => $value ) {
if ( $dif >= $value ) {
$time = round( $dif / $value );
$dif %= $value;
$output .= ( $output ? ' ' : '' ) . $time . ' ';
$output .= ( ( $time > 1 ) ? $key . 's' : $key );
$granularity --;
}
if ( $granularity == 0 )
break;
} // foreach( $periods as $key => $value )
if($future) {
return "In " . ($output ? $output : '0 seconds');
} else {
return ($output ? $output : '0 seconds') . ' ago';
}
} else
return date( $format, $ts );
}
This should work
<?php
function diffPeriods($diff)
{
$periods = array(
'Week' => 604800,
'Day' => 86400,
'Hour' => 3600,
'Minute' => 60,
'Second' => 1
);
$granularity = 1;
$output = '';
foreach ($periods as $key => $value) {
if ($diff >= $value) {
$time = round($diff / $value);
$diff %= $value;
$output .= ($output ? ' ' : '') . $time . ' ';
$output .= (($time > 1) ? $key . 's' : $key);
$granularity --;
}
if ($granularity == 0) {
break;
}
}
return $output;
}
function time_ago($ts, $format)
{
$diff = time() - $ts;
if ($diff == 0) {
return 'Now';
}
if ($diff < 604800 && $diff > 0) {
// 604800 7 days / 864000 10 days
$periods = array(
'Week' => 604800,
'Day' => 86400,
'Hour' => 3600,
'Minute' => 60,
'Second' => 1
);
$output = diffPeriods($diff);
return ($output ? $output : '0 seconds') . ' ago';
} elseif ($diff < 0 && $diff > - 604800) {
$output = diffPeriods($diff * - 1);
return 'in ' . ($output ? $output : '0 seconds');
}
// too old/new...display the date
return date($format, $ts);
}
var_dump(time_ago(time(), 'l, F d, Y H:i')); // now
var_dump(time_ago(time() + 3600, 'l, F d, Y H:i')); // 1 hour in the future
var_dump(time_ago(time() + (3600 * 50), 'l, F d, Y H:i')); // 2 daysin the future
var_dump(time_ago(time() + (3600 * 24 * 11), 'l, F d, Y H:i')); // 11 days in the future
var_dump(time_ago(time() - 3600, 'l, F d, Y H:i')); // 1 hour ago
var_dump(time_ago(time() - (3600 * 50), 'l, F d, Y H:i')); // 2 days ago
var_dump(time_ago(time() - (3600 * 24 * 11), 'l, F d, Y H:i')); // 11 days ago
For a rent application, I have an array $dates like this:
Array
(
[2013-07-19] => 1
[2013-07-21] => 3
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
[2013-07-30] => 3
[2013-07-31] => 1
)
The date is the key, and the values are the number of items rent in that day for a specific product
How can I split this array in many sub arrays containing each a list of consecutive days?
Like this:
Array
(
[0] => Array
(
[2013-07-19] => 1
)
[1] => Array
(
[2013-07-21] => 3
)
[2] => Array
(
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
)
[3] => Array
(
[2013-07-30] => 3
[2013-07-31] => 1
)
)
$newArray = array();
foreach ($array as $date => $value)
{
// Make sure the newArray starts off with at least one element
if (empty($newArray))
$newArray[] = array();
// Calculate the difference in dates.
// (I like using DateTime, but use whichever method you like)
$dateTime = new DateTime($date);
$lastDateTime = new DateTime($lastDate);
$dateDiff = $dateTime->diff($lastDateTime);
// Add a new array to the end if the difference between this element and the last was more than a day
if ($dateDiff->days > 1)
$newArray[] = array();
// We can now be guaranteed that the last element of $newArray is the one we want to append to
$newArray[count($newArray) - 1][$date] = $value;
// Keep track of the last date you saw
$lastDate = $date;
}
Here it is in action: https://eval.in/38039
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = end(explode('-', next($array[$date])));
if ($thisDay + 1 != $nextDay + 0)
$i++;
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
}//END FOREACH LOOP
This is the code i would use to do what you are asking.
UPDATE:
I was wrong above. i have altered the code to work this time:
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = array_key_exists(date('Y-m-d', strtotime($date . ' +1 day')), $array);
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
if (!$nextDay)
$i++;
}//END FOREACH LOOP
Here is my test case:
<?php
$array = array(
'2013-07-19' => 1,
'2013-07-21' => 3,
'2013-07-23' => 2,
'2013-07-24' => 4,
'2013-07-25' => 4,
'2013-07-26' => 2,
'2013-07-27' => 2,
'2013-07-30' => 3,
'2013-07-31' => 1
);
echo '<pre>' . print_r($array, true) . '</pre>';
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = array_key_exists(date('Y-m-d', strtotime($date . ' +1 day')), $array);
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
if (!$nextDay)
$i++;
}//END FOREACH LOOP
echo '<pre>' . print_r($newArray, true) . '</pre>';
?>
you can do it like this:
$data = array(
'2013-07-19' => 1,
'2013-07-21' => 3,
'2013-07-23' => 2,
'2013-07-24' => 4,
'2013-07-25' => 4,
'2013-07-26' => 2,
'2013-07-27' => 2,
'2013-07-30' => 3,
'2013-07-31' => 1
);
$result = array();
$ref = new DateTime('1821-11-11');
foreach ($data as $datum => $nb) {
if ($ref->add(new DateInterval('P1D'))->format('Y-m-d')!=$datum) {
$result[] = array();
$ref = new DateTime($datum);
}
$result[array_pop(array_keys($result))][$datum] = $nb;
}
print_r($result);
What is the most efficient way to get an array of months, from a specified date, up until the present day, grouped by year.
Eg getMonths("August 2012") would output
array(
array("Year"=>"2013", "months" = array(
"February", "January")
),
array("Year"=>"2012", "months" = array(
"December", "November","October", "September", "August")
)
)
So far I've got:
$start = strtotime('2012-08-01');
$end = time();
$month = $start;
$months[] = date('F', $start);
while($month <= $end) {
$month = strtotime("+1 month", $month);
$months[] = date('F', $month);
}
This is outputting the correct months, but not grouping them into years.
Thanks
You can try
function getMonths($month,$count = 1) {
$now = new DateTime();
$start = DateTime::createFromFormat("F Y", $month);
$list = array();
$interval = new DateInterval(sprintf("P%dM",$count));
while ( $start <= $now ) {
$list[$start->format("Y")][] = $start->format("F");
$start->add($interval);
}
return $list;
}
print_r(getMonths("August 2012"));
Output
Array
(
[2012] => Array
(
[0] => August
[1] => September
[2] => October
[3] => November
[4] => December
)
[2013] => Array
(
[0] => January
[1] => February
)
)
Since the answer posted here did not work for me (also tried online sandbox to be sure) i wrote a method that works with the very most versions of PHP:
function getMonths($monat, $year) {
$list = array();
for(;$monat <= 12;$monat++) {
if($year == date("Y") && $monat == date("m")) { // exit on current month+year
break;
}
if(!isset($list[ $year ])) {
$list[ $year ] = array();
}
$list[ $year ][ str_pad($monat, 2, '0', STR_PAD_LEFT) ] = date("F", strtotime('01.' . $monat . '.' . $year));
if($monat == 12) {
$monat = 0;
$year++;
}
}
return $list;
}
Working with an array of dates (opening times for a business). I want to condense them to their briefest possible form.
So far, I started out with this structure
Array
(
[Mon] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu] => 12noon-2:45pm, 5:30pm-10:30pm
[Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
What I want to achieve is this:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
I've tried writing a recursive function and have managed to output this so far:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
Can anybody see a simple way of comparing the values and combining the keys where they're similar? My recursive function is basically two nested foreach() loops - not very elegant.
Thanks,
Matt
EDIT: Here's my code so far, which produces the 3rd array above (from the first one as input):
$last_time = array('t' => '', 'd' => ''); // blank array for looping
$i = 0;
foreach($final_times as $day=>$time) {
if($last_time['t'] != $time ) { // it's a new time
if($i != 0) { $print_times[] = $day . ' ' . $time; }
// only print if it's not the first, otherwise we get two mondays
} else { // this day has the same time as last time
$end_day = $day;
foreach($final_times as $day2=>$time2) {
if($time == $time2) {
$end_day = $day2;
}
}
$print_times[] = $last_time['d'] . '-' . $end_day . ' ' . $time;
}
$last_time = array('t' => $time, 'd' => $day);
$i++;
}
I don't think there is a particularly elegant solution to this. After much experimenting with the built in array_* functions trying to find a nice simple solution, I gave up and came up with this:
$lastStart = $last = $lastDay = null;
$new = array();
foreach ($arr as $day => $times) {
if ($times != $last) {
if ($last != null) {
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
}
$lastStart = $day;
$last = $times;
}
$lastDay = $day;
}
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
It only uses one foreach loop as opposed to your two, as it keeps a bunch of state. It'll only merge adjacent days together (i.e., you won't get something like Mon-Tue,Thu-Fri if Wednesday is changed, you'll get two separate entries).
I'd approach it by modelling it as a relational database:
day start end
1 12:00 14:45
1 17:30 22:30
...
Then its fairly easy to reduce - there are specific time intervals:
SELECT DISTINCT start, end
FROM timetable;
And these will occur on specific days:
SELECT start, end, GROUP_CONCAT(day) ORDER BY day SEPERATOR ','
FROM timetable
GROUP BY start,end
(this uses the MySQL-only 'group_concat' function - but the method is the same where this is not available)
would give:
12:00 14:45 1,2,3,4,5
17:30 22:30 1,2,3,4,5
12:00 23:00 6
12:00 21:30 7
Then it's fairly simple to work out consecutive date ranges from the list of days.
C.
As an alternative, I managed to cobble together a version using array_* functions. At some point though, 'elegance', 'efficiency' and 'readability' all packed up and left. It does, however, handle the edge cases I mentioned in the other answer, and it left me with a nice warm glow for proving it could be done in a functional manner (yet at the same time a sense of shame...)
$days = array_keys($arr);
$dayIndices = array_flip($days);
var_dump(array_flip(array_map(
function ($mydays) use($days, $dayIndices) {
return array_reduce($mydays,
function($l, $r) use($days, $dayIndices) {
if ($l == '') { return $r; }
if (substr($l, -3) == $days[$dayIndices[$r] - 1]) {
return ((strlen($l) > 3 && substr($l, -4, 1) == '-') ? substr($l, 0, -3) : $l) . '-' . $r;
}
return $l . ',' . $r;
}, '');
}, array_map(
function ($day) use ($arr) {
return array_keys($arr, $arr[$day]);
}, array_flip($arr)
)
)));
I tested it with this input:
'Mon' => '12noon-2:45pm, 5:30pm-10:30pm',
'Tue' => '12noon-2:45pm, 5:30pm-10:30pm',
'Wed' => '12noon-2:45pm, 5:30pm-10:00pm',
'Thu' => '12noon-2:45pm, 5:30pm-10:30pm',
'Fri' => '12noon-2:45pm, 5:30pm-10:00pm',
'Sat' => '12noon-2:45pm, 5:30pm-10:30pm',
'Sun' => '12noon-9:30pm'
And got this:
["Mon-Tue,Thu,Sat"]=> string(29) "12noon-2:45pm, 5:30pm-10:30pm"
["Wed,Fri"]=> string(29) "12noon-2:45pm, 5:30pm-10:00pm"
["Sun"]=> string(13) "12noon-9:30pm"
Basically, the array_map at the end transforms the input into an associative array of times to an array of days that they occur on. The large block of code before that reduces those days into a nicely formatted string using array_reduce, consulting the $days and $dayIndices arrays to check if days are consecutive or not.