Creating an associative multidimensional array in PHP - php

I'm trying to create an array where the Month is the key and each key contains one or more dates within them. I start with an array that looks like $arr below. Sidenote: I do not control how the original array is structured as it comes from an API. I merely added the below $arr to illustrate and make it easier for people to understand and debug.
$arr = array(
0 => array(
'date' => '2020-12-07'
),
1 => array(
'date' => '2020-12-19'
),
2 => array(
'date' => '2021-01-03'
),
3 => array(
'date' => '2020-01-18'
)
);
Because I need to display the dates differently than this, I need to construct an array which contains the Month name and a formated date:
$sorted = array(); // This is the array I will return later.
foreach ( $arr as $day ) {
setlocale(LC_TIME, 'sv_SE');
$month = strftime( '%B', strtotime( $day['date'] ) );
$display_date = trim( strftime( '%e %b', strtotime( $day['date'] ) ) );
}
Everything I've tried doing here so far has failed. I can't even remember all methods to be honest. The last I tried was this (within the foreach()):
array_push($sorted, array(
$month => $display_date
));
The var_dump() of that, generated an enumerated array:
array (size=4)
0 =>
array (size=1)
'December' => string '7 Dec' (length=5)
1 =>
array (size=1)
'December' => string '19 Dec' (length=6)
2 =>
array (size=1)
'Januari' => string '3 Jan' (length=5)
3 =>
array (size=1)
'Januari' => string '18 Jan' (length=6)
What I'm trying to achieve is this:
All $display_date's should sit under its $month key. The $month key must be unique and contain all dates for that month.
Thankful for any help that gets me in the right direction here because I feel like I'm doing something fundamentally wrong.

You are appending new array with month and date every loop, replace array_push() with $sorted[$month][] = $display_date;
foreach ( $arr as $day ) {
setlocale(LC_TIME, 'sv_SE');
$month = strftime( '%B', strtotime( $day['date'] ) );
$display_date = trim( strftime( '%e %b', strtotime( $day['date'] ) ) );
$sorted[$month][] = $display_date;
}
print_r($sorted);
Output:
Array
(
[december] => Array
(
[0] => 7 dec
[1] => 19 dec
)
[januari] => Array
(
[0] => 3 jan
[1] => 18 jan
)
)

Related

Search Array for Best Match based on Day & Time

I'm trying to work out how to the the correct Site base on the current Day and Time from an array. The examples array just shows Monday, the real array will contain 7 days of the week with multiple values for each day.
This is the example array :
$arr = array (
array( 'Day' => 'Monday',
'Start' => '0830',
'End' => '1730',
'Site' => 'NW1'),
array( 'Day' => 'Monday',
'Start' => '1200',
'End' => '1300',
'Site' => 'PL1'),
array( 'Day' => 'Monday',
'Start' =>'1730',
'End' => '2130',
'Site' => 'RE1')
);
So Monday at 1100 I should get NW1, at 1800 I should get RE1, but between 1200-1300 I should get PL1
So far this is the code I have:
$today = 'Monday'; // Full day name
$time = '1205';
echo "<br/>Day: $today";
echo "<br/>Time: $time <br/><br/>";
$arr = array (
array( 'Day' => 'Monday',
'Start' => '0830',
'End' => '1730',
'Site' => 'NW1'),
array( 'Day' => 'Monday',
'Start' => '1200',
'End' => '1300',
'Site' => 'PL1'),
array( 'Day' => 'Monday',
'Start' =>'1730',
'End' => '2130',
'Site' => 'RE1')
);
usort($arr, function($a, $b) {
return (date("N", strtotime($a['Day'])) <=> date("N", strtotime($b['Day']))) * 100 +
($a['Start'] <=> $b['Start']) * 10 +
($a['End'] <=> $b['End']);
});
foreach ($arr as $i => $values) {
if ($today != $values['Day']) continue;
if ($time >= $values['Start'] && $time <= $values['End']) {
$site = $values['Site'];
break;
}
}
echo "$today # $time Site => $site";
This works for times between 0830-1730 & 1730-2130, but not if the time is 1200-1300.
I'm assuming I need to search the array for the Day match, then the Start time and check the end time, but I'm not sure how to do this ?
Can anyone point me in the right direction.
Thanks
**** UPDATE ****
New example array with additional entries
Array
(
[0] => Array
(
[Day] => Monday
[Start] => 0830
[End] => 1730
[Site] => NW1
)
[1] => Array
(
[Day] => Monday
[Start] => 0930
[End] => 0945
[Site] => PK1
)
[2] => Array
(
[Day] => Monday
[Start] => 1200
[End] => 2100
[Site] => PL1
)
[3] => Array
(
[Day] => Monday
[Start] => 1230
[End] => 1245
[Site] => EM1
)
[4] => Array
(
[Day] => Monday
[Start] => 1730
[End] => 2130
[Site] => RE1
)
}
The expected results are:
0940 = PK1
1430 = PL1
0920 = NW1
The aim is 0830 to 1730 NW1 is correct unless something else overrides this, ie 1200-2100 PL1 would be correct, after 2100 to 2130 RE1 etc.
Thanks
All you need to do is reverse the sorting based on start time
usort($arr, function($a, $b) {
return (date("N", strtotime($a['Day'])) <=> date("N", strtotime($b['Day']))) * 100 +
($b['Start'] <=> $a['Start']) * 10 +
($a['End'] <=> $b['End']);
});
This way, we will loop through the array starting with the latest start time (for each day) and once we find a match, we break the loop, using the site value for the match.
I'm still not really sure of the purpose of the multiplication in your usort, but it doesn't seem to be causing any problems, so I'm going to leave it in.
DEMO
As far as I can see as soon as you find a $time between the "start" and "end" you assign the value to $site and then "break" straight away without looking through the rest of the array.
But if the time is 1230 on a Monday which entry in the array should take precedence?
If it is the last one, then maybe hang on to a variable until you search the entire array like so:
$lastCorrectEntry;
foreach ($arr as $i => $values) {
if ($today != $values['Day']) continue;
if ($time >= $values['Start'] && $time <= $values['End']) {
$lastCorrectEntry = $values['Site'];
}
}
$site = $lastCorrectEntry;

assign variable for nested array and spliting it

I am getting nested array reply. It is contain date, time and day I want to break that. How can i do that.
This is my reply
Array
(
[code] => 202
[message] => Accepted
[data] => Array
(
[result] => Array
(
[15:45~31-10-2016 Mon] => Array
(
[Sday] =>
[Ttime] => 15:45
[Smonth] =>
"[15:45~31-10-2016 Mon] => Array" how to assign variable and how can i break this into day ,date and time variable
As mentioned in Mohammad's comment on your question,
You should use preg_split function.
$str = key($array['data']['result']); // 15:45~31-10-2016 Mon
$res = preg_split("/[~\s]/", $str);
echo '<pre>'; print_r($res);
output:-
Array
(
[0] => 15:45
[1] => 31-10-2016
[2] => Mon
)
If you have only single element in result array, use extract and explode to retrieve the values from man array: Something like -
$result = $array['data']['result'];
$date = key($result);
$day = extract($result[$date]);
var_dump($date); // 15:45~31-10-2016 Mon
var_dump($Ttime); // will output 15:45
$date = explode(' ', $date);
$dateString = substr($date[0], strpos($date[0], "{$Ttime}~") + 1); //31-10-2016
$week = $date[1]; // var_dump($week); will give `Mon`
Given:
$result = array(
'code' => '202',
'message' => 'Accepted',
'data' => array(
'result' => array(
'15:45~31-10-2016 Mon' => array(
'Sday' => '',
'Ttime' => '15:45',
'Smonth' => ''
)
)
)
);
you can do this:
$data = $result['data']['result'];
$dateKey = key($data);
$dateString = preg_split("/[~\s]/", $dateKey);
$date = array(
'day' => $dateString[2],
'date' => $dateString[1],
'time' => $dateString[0]
);
var_dump($date);
or this:
$data = $result['data']['result'];
$dateKey = key($data);
$dateString = preg_replace("/[~\s]/", ' ', $dateKey);
$dateObj = DateTime::createFromFormat('H:i d-m-Y D', $dateString);
$date = array(
'day' => $dateObj->format('D'),
'date' => $dateObj->format('m-d-Y'),
'time' => $dateObj->format('H:i')
);
var_dump($date);

Selecting a certain item from multi-dimensional array

I have an multi-dimensional array called shifts which contains the day (e.g. Monday) and then the shift (e.g. 12:00 - 16:00)
I'm looking to do something like:
$monday = shift from array where day equals Monday
My array currently looks like:
Array ( [0] => Array ( [day] => Saturday [shift] => Day Off! )
[1] => Array ( [day] => Sunday [shift] => Day Off! )
[2] => Array ( [day] => Monday [shift] => 11:00-19:00 )
[3] => Array ( [day] => Tuesday [shift] => 08:00-17:00 )
[4] => Array ( [day] => Wednesday [shift] => 08:00-17:00 )
[5] => Array ( [day] => Thursday [shift] => 16:00-01:00 )
[6] => Array ( [day] => Friday [shift] => 16:00-01:00 ) )
Array is built using this code:
$shifts = array();
$sql = mysql_query("SELECT day, shift FROM ps_shifts WHERE user_id = '$user_id' AND week_begin = '$week_1_begin'");
while($row = mysql_fetch_assoc($sql)) {
$shifts[] = $day;
}
/* to refine on what was said above lets take the the data as such:*/
$data = array(
array ( 'day' => 'Saturday', 'shift' => 'Day Off!' ),
array ( 'day' => 'Sunday', 'shift' => 'Day Off!' ),
array ( 'day' => 'Monday', 'shift' => '11:00-19:00' ),
/* ... */
);
/* we then take that data and transform it, that is flatten it to day=>shift. call it shifts*/
$shifts = array();
$days = array('Saturday','Sunday','Monday','Tuesday','Wednesday','Thursday', 'Friday');
foreach ($data as $i=>$s) {
$shifts[$days[$i]] = $data[$i]['shift'];
}
/* this returns an array like:
$shifts = array (
'Saturday' => 'Day Off!',
'Sunday' => 'Day Off!',
'Monday' => '11:00-19:00',
);
*/
/* then to get the shift for any day is as simple as.*/
$monday_shift = $shifts['Monday'];
print "monday shift is: $monday_shift\n";
You could use the day as the array key.
So:
while($row = mysql_fetch_assoc($sql)) {
$shifts[$day['day']] = $day;
}
Then you could get it by doing this:
$shift_time = $shifts['Monday']['shift'];
Solved based on 'jd182' anwser, however the provided code didn't work so I modified to this:
$shifts = array();
$sql = mysql_query("SELECT day, shift FROM ps_shifts WHERE user_id = '$user_id' AND week_begin = '$week_1_begin'");
while($row = mysql_fetch_assoc($sql)) {
$shifts[$row['day']] = $row['shift'];
}
echo $shifts['Monday'];

Grouping an array with intersecting dates for calendar day view

Doing a personal project, making a calandar with just php. I simply cannot figure out a way to group arrays based on intersecting dates so that I can draw them on a grid. Something that looks like this
http://calendar.oregonstate.edu/docs/img/day_view_advanced.gif (cant post image yet)
original array
array
0 =>
array (size=7)
'ID' => string '6188' (length=4)
'name' => string 'test' (length=32)
'dt_start' => string '2012-10-04 10:00:00' (length=19)
'dt_end' => string '2012-10-04 11:00:00' (length=19)
assuming that there are several events most with over lapping dates. Here is the function I use to check if dates intersects and it works.
function Intersect ($date, $cDate, $start, $end) {
return ($date == $start) || ($date > $start ? $date <= $end : $start < $cDate);
}
I don't have a problem with the actual drawing, but trying to group the arrays so that it places them appropriately on the grid.
//$e is the events
foreach ($e as $k => $a) {
$oStart1 = new DateTime( $a ['dt_start'] );
$oEnd1 = new DateTime( $a ['dt_end'] );
foreach ($e as $i => $b) {
if ( $a['ID'] == $b['ID'] )
continue;
$oStart2 = new DateTime( $b ['dt_start'] );
$oEnd2 = new DateTime( $b ['dt_end'] );
if ( Intersect ($oStart1, $oEnd1, $oStart2, $oEnd2) ) {
$intersect[$a['ID']] = $a;
}
}
}
This groups ALL dates that intersect each other. This has been driving me crazy since I just can't figure out a way to split the $intersect array into different groups so that I can set the width correctly. optimally I would like the resulting array to look like this
$group[ 1 ] = array (
array (
'start_time' => '2012-10-04 10:00:00',
'end_time' => '2012-10-04 12:00:00'
),
array (
'start_time' => '2012-10-04 10:30:00',
'end_time' => '2012-10-04 11:40:00'
),
array (
'start_time' => '2012-10-04 11:00:00',
'end_time' => '2012-10-04 12:00:00'
)
);
$group[ 2 ] = array (
array (
'start_time' => '2012-10-04 13:00:00',
'end_time' => '2012-10-04 14:00:00'
),
array (
'start_time' => '2012-10-04 13:30:00',
'end_time' => '2012-10-04 13:40:00'
)
);
I know there a libraries that do this ie jquery full calendar plugin is pretty good but I'm trying to learn more about programming. Any help or links to point me at the right direction would be awesome.

php function to get dates of last 7 weeks

I am trying to build a php function that would return an array with the start date and end date of the last n number of weeks. this would include the current week. It would look something like this:
function lastnweeks(n)
{
//the code. I am not asking for the code itself but ideas on how to accomplish this
return $array;
}
$lastnweeks =lastnweeks(2);
print_r($lastnweeks);
this would print:
Array (
[0] => Array (
[0] => 2010/09/20
[1] => 2010/09/26
)[1] => Array (
[0] => 2010/09/13
[1] => 2010/09/19
))
I wouldn't use an absolute number of seconds because of daylight savings time and leapyears/leapseconds. You can let PHP's strtotime() function take care of this for you by using relative dates. Each iteration through a loop you can simply tell the function to find "Last Monday", and then use that result as your starting point for the next iteration.
The code:
$past_weeks = 7;
$relative_time = time();
$weeks = array();
for($week_count=0;$week_count<$past_weeks;$week_count++) {
$monday = strtotime("last Monday", $relative_time);
$sunday = strtotime("Sunday", $monday);
$weeks[] = array(
date("Y-m-d", $monday),
date("Y-m-d", $sunday),
);
$relative_time = $monday;
}
var_dump($weeks);
The output:
array
0 =>
array
0 => string '2010-09-20' (length=10)
1 => string '2010-09-26' (length=10)
1 =>
array
0 => string '2010-09-13' (length=10)
1 => string '2010-09-19' (length=10)
2 =>
array
0 => string '2010-09-06' (length=10)
1 => string '2010-09-12' (length=10)
3 =>
array
0 => string '2010-08-30' (length=10)
1 => string '2010-09-05' (length=10)
4 =>
array
0 => string '2010-08-23' (length=10)
1 => string '2010-08-29' (length=10)
5 =>
array
0 => string '2010-08-16' (length=10)
1 => string '2010-08-22' (length=10)
6 =>
array
0 => string '2010-08-09' (length=10)
1 => string '2010-08-15' (length=10)
Use strtotime to get the monday and then subtract the number of seconds for each week:
function lastnweeks($n) {
$time = strtotime('Monday 00:00:00+0000');
$arr = array();
while ($n-- > 0) {
$arr[] = array_reverse(array(
date('Y/m/d', $time-=86400), // sunday
date('Y/m/d', $time-=6*86400) // monday
));
}
return $arr;
}
array_reverse is used to reverse the array as the calculation walks backwards.
Take your pick
$last_week = strtotime('last Week');
echo "Last Week ".date("Y/m/d", $last_week)."<br />\n";
or
$last_week = mktime(0,0,0,date("m"),date("d")-7,date("Y"));
echo "Last Week ".date("Y/m/d", $last_week)."<br />\n";

Categories