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.
Related
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
)
)
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;
I have this array filled with data from a database
$collectTable1 = array( 'errand' => $interest->errand_id,
'timestamp' => $interest->timestamp,
'type' => $interest->type,
'amount' => $interest->amount
);
$collector[] = $collectTable1;
And i want to rsort the timestamp, like this
$sortTime = rsort($collectedData['timestamp']);
I tried this, and i get this output
function timesort($a, $b) {
return (intval($a['timestamp']) > intval($b['timestamp']));
}
usort($collector, "timesort");
2017-12-01 10:53:26
I tought i would get from the descending date point? Something like
2018-09-04 12:32:16.
My timestamp also contains both unixtimestamp and regular dates like this "
2017-12-01 10:53:26"
I guessing you have array of element in $collector.
If you want to sort those by the timestamp you can use usort
Consider the following example:
$collector = array();
$e1 = array("errand" => 1, "timestamp" => "2017-12-01 10:53:26");
$e2 = array("errand" => 2, "timestamp" => "2018-07-01 10:53:26");
$e3 = array("errand" => 3, "timestamp" => "2018-12-01 10:53:26");
$collector = array($e1, $e2, $e3);
function cmp($a, $b)
{
return (strtotime($a['timestamp']) < strtotime($b['timestamp']));
}
usort($collector, "cmp");
When your timestamp values are in string use strtotime to convert them to EPOC before compare.
Now, the $collector array elements are sorted by the timestamp value.
Output of the code example is:
Array
(
[0] => Array
(
[errand] => 3
[timestamp] => 2018-12-01 10:53:26
)
[1] => Array
(
[errand] => 2
[timestamp] => 2018-07-01 10:53:26
)
[2] => Array
(
[errand] => 1
[timestamp] => 2017-12-01 10:53:26
)
)
Once you have your array:
<?php
$data = [
['timestamp' => '100'],
['timestamp' => '300'],
['timestamp' => '200']
];
usort($data, function($a, $b) {
return $b['timestamp'] <=> $a['timestamp'];
});
var_export($data);
Output:
array (
0 =>
array (
'timestamp' => '300',
),
1 =>
array (
'timestamp' => '200',
),
2 =>
array (
'timestamp' => '100',
),
)
If you have multiple value for all key of associative array $collectTable1 than
foreach($interest as $i){
$collectTable1 = array( 'errand' => array($i->errand_id),
'timestamp' => array($i->timestamp),
'type' => array($i->type),
'amount' => array($i->amount)
);
rsort($collectTable1[‘timestamp’]);
Here collectTable1 is an associative array of one dimensional arrays ie.
$collectTable1[‘timestamp’][0]=firstvalue
$collectTable1[‘timestamp’][1]=secondvalue
And so on
This question already has answers here:
Sort multidimensional array by multiple columns
(8 answers)
Closed last month.
I have multidimensional array in PHP. Something like
$mylist = array(
array('ID' => 1, 'title' => 'Hello', 'datetime' => '2014-05-05 12:08 PM'),
array('ID' => 2, 'title' => 'Amazing Pic', 'datetime' => '2014-05-06 11:08 PM'),
array('ID' => 3, 'title' => 'Style', 'datetime' => '2014-05-02 9:08 PM'),
array('ID' => 4, 'title' => 'Hello World', 'datetime' => '2014-05-01 5:08 PM')
);
My question is how do I sort by title and datetime? I spent quite some time searching on this. But I just found sort by two columns but with the same data type. I am now struggling to do this because I believe mine involve strtotime() function as this involves time.
This is what I have at this moment
function querySort ($x, $y) {
return strcasecmp($x['title'], $y['title']);
}
function cmp($a, $b){
$ad = strtotime($a['datetime']);
$bd = strtotime($b['datetime']);
return ($ad-$bd);
}
usort($mylist , 'querySort');
usort($mylist , 'cmp');
Could anyone help me on how to achieve this?
The second usort overrides the output of the first usort.
What you need to do is merge the 2 sorting functions to order themselves by title and then date time.
Pseudocode would be :
function SortByTitleAndDateTime($a,$b)
1) SortByTitle and return the value if it is non zero.
2) If SortByTitle is zero (meaning the 2 values are the same in terms of title),
do SortByDateTime
In the end, you'd only need to call usort(array, SortByTitleAndDateTime).
It looks like you need array_multisort. You can visit following link for more information http://www.php.net//manual/en/function.array-multisort.php
The basic idea would be cleared from example#2 on above link.
Try this,
$mylist = array(
array('ID' => 1, 'title' => 'Hello', 'datetime' => '2014-05-05 12:08 PM'),
array('ID' => 2, 'title' => 'Amazing Pic', 'datetime' => '2014-05-06 11:08 PM'),
array('ID' => 3, 'title' => 'Style', 'datetime' => '2014-05-02 9:08 PM'),
array('ID' => 4, 'title' => 'Hello World', 'datetime' => '2014-05-01 5:08 PM'),
array('ID' => 5, 'title' => 'Boy', 'datetime' => '2014-05-01 5:08 PM')
);
// Obtain a list of columns
foreach ($mylist as $key => $row) {
$dTime[$key] = $row['datetime'];
$title[$key] = $row['title'];
}
// Sort the data with dTimedescending, titleascending
// Add $mylist as the last parameter, to sort by the common key
array_multisort($dTime, SORT_DESC, $title, SORT_ASC, $mylist);
Your output will be
Array
(
[0] => Array
(
[ID] => 2
[title] => Amazing Pic
[datetime] => 2014-05-06 11:08 PM
)
[1] => Array
(
[ID] => 1
[title] => Hello
[datetime] => 2014-05-05 12:08 PM
)
[2] => Array
(
[ID] => 3
[title] => Style
[datetime] => 2014-05-02 9:08 PM
)
[3] => Array
(
[ID] => 5
[title] => Boy
[datetime] => 2014-05-01 5:08 PM
)
[4] => Array
(
[ID] => 4
[title] => Hello World
[datetime] => 2014-05-01 5:08 PM
)
)
I have added ID no 5 for demonstration, so that date wise sorted in descending order and title wise sorted in ascending order
I ended up with something like Mark Gabriel's logic. This will sort out the title first, and followed by the date time. So here it is:
function SortByTitleAndDateTime($a,$b){
if ( strcasecmp($a['title'], $b['title']) != 0 ){
return strcasecmp($a['title'], $b['title']);
}
else{
$ad = strtotime($a['datetime']);
$bd = strtotime($b['datetime']);
return ($ad-$bd);
}
}
usort($mylist, 'SortByTitleAndDateTime');
Hope this helps other people as well.
This question already has answers here:
PHP Sort a multidimensional array by element containing Y-m-d H:i:s date
(11 answers)
Closed 11 months ago.
I have an array like the following:
Array
(
[0] => Array
(
'name' => "Friday"
'weight' => 6
)
[1] => Array
(
'name' => "Monday"
'weight' => 2
)
)
I would like to grab the last values in that array (the 'weight'), and use that to sort the main array elements. So, in this array, I'd want to sort it so the 'Monday' element appears before the 'Friday' element.
You can use usort as:
function cmp($a, $b) {
return $a['weight'] - $b['weight'];
}
usort($arr,"cmp");
Can be done using an anonymous function.
Also if your 'weight' is a string use one of the other returns (see the commented out lines):
<?php
$arr = array(
0 => array (
'name' => 'Friday',
'weight' => 6,
),
1 => array (
'name' => 'Monday',
'weight' => 2,
),
);
// sort by 'weight'
usort($arr, function($a, $b) { // anonymous function
// compare numbers only
return $a['weight'] - $b['weight'];
// compare numbers or strings
//return strcmp($a['weight'], $b['weight']);
// compare numbers or strings non-case-sensitive
//return strcmp(strtoupper($a['weight']), strtoupper($b['weight']));
});
var_export($arr);
/*
array (
0 => array (
'name' => 'Monday',
'weight' => 2,
),
1 => array (
'name' => 'Friday',
'weight' => 6,
),
)
*/
You can also use an anonymous function.
usort($items, function($a, $b) {
return $a['name'] > $b['name'];
});
Agree with usort, I also sometimes use array_multisort (http://ca2.php.net/manual/en/function.usort.php) example 3, sorting database results.
You could do something like:
<?php
$days = array(
array('name' => 'Friday', 'weight' => 6),
array('name' => 'Monday', 'weight' => 2),
);
$weight = array();
foreach($days as $k => $d) {
$weight[$k] = $d['weight'];
}
print_r($days);
array_multisort($weight, SORT_ASC, $days);
print_r($days);
?>
Output:
Array
(
[0] => Array
(
[name] => Friday
[weight] => 6
)
[1] => Array
(
[name] => Monday
[weight] => 2
)
)
Array
(
[0] => Array
(
[name] => Monday
[weight] => 2
)
[1] => Array
(
[name] => Friday
[weight] => 6
)
)
If the filed you sort by is string like title name,
array_multisort + Flags for Natural Sorting and CaseInSensitivity are the way to go:
$sort_by_title = array();
foreach($items as $item) {
$sort_by_title [] = $item['title'];
}
array_multisort($sort_by_title , SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $items );
NOTE, if the element you are sorting on is a float like .0534 and .0353 (like for a percentage), then you have to multiply both by 1000. not sure why frankly... it appears that usort seems to compare the integer values.
took me awhile to figure that one out...
and 2 tips that may not be immediately obvious:
if your arrays are objects, you can use return $a->weight - $b->weight of course
if you return $b->weight - $a->weight, it will sort desending.
Here's a cool function that might help:
function subval_sort($a,$subkey,$sort) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
if($b)
{
$sort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
}
Send in the array as $a the key as $subkey and 'asort' or 'sort' for the $sort variable