I have an array which holds start and end dates like the following:
$dates[] = array('start'=> '2015-01-01', 'end'=> '2016-05-01');
$dates[] = array('start'=> '2016-01-01', 'end'=> '2016-09-11');
$dates[] = array('start'=> '2017-01-05', 'end'=> '2018-02-01');
$dates[] = array('start'=> '2017-01-01', 'end'=> '2017-05-05');
I want to merge the dates together and remove overlapping dates to produce a new array of dates without any overlap. The result of the above would be:
[0] => Array
(
[start] => 2015-01-01
[end] => 2016-09-11
)
[1] => Array
(
[start] => 2017-01-01
[end] => 2018-02-01
)
I'm rather stuck on this. Any ideas on how this could be done?
Since the late hour of the night it will probably not be the most elegant code, but you will get the idea:
First you want to sort the array by start date:
usort($dates, function($a, $b) {
return strtotime($a["start"]) - strtotime($b["start"]);
});
Then you want to initialize the result array, and two more variables to hold the last $start and $end times.
Now you iterate the array and only push a new row if the current start date is bigger than the last end date. If so, you also set the last $start date to the current one. The last $end date you always set to the biggest (compare between current and last).
After the iteration you want to add the last row which your $start and $end variables are holding.
$result = [];
$start = null;
$end = null;
function addToResult(&$result, &$start, &$end, &$date = null)
{
if (!$date || !$start || strtotime($date["start"]) > strtotime($end)) {
if ($start && $end) {
$result[] = ["start" => $start, "end" => $end];
}
if ($date) {
$start = $date["start"];
$end = $date["end"];
}
}
$end = $date && strtotime($end) < strtotime($date["end"]) ? $date["end"] : $end;
}
foreach ($dates as $date) {
addToResult($result, $start, $end, $date);
}
addToResult($result, $start, $end);
https://3v4l.org/Ej40b
This question already has answers here:
How to sort date array in php?
(8 answers)
Closed 1 year ago.
I need to sort an array from the smallest date. I used Usort, but it order the array considering just the day. I tried using a code from an example using sort in javascript but i need this happen in php or find a way to convert php array to js.
Here is the code:
<?php
ArrayDates ( [0] => 22/03/2018 [1] => 09/04/2018 [2] => 26/03/2018
[3] => 27/11/2017 [4] => 22/01/2018 [5] => 06/09/2017 )
?>
<script>
ArrayDates.sort(function (a, b){
var aa = a.split('-'),
bb = b.split('-');
return aa[2] - bb[2] || aa[1] - bb[1] || aa[0] - bb[0];
})
</script>
Hi finally i found a solution in a forum and maybe can help to someone else. The solution is create a new array of timestamps based on the original array. Then sort this new array. After just echo the first element of the new array with "date" and will return the first date. Here is the code:
<?php
$ArrayDates= array ('22/03/2018','09/04/2018', '26/03/2018',
'27/11/2017','22/01/2018', '06/09/2017');
function date_to_timestamp($d){
$newarr = array();
foreach($d as $f) {
$arr=explode("/",$f);
array_push($newarr, mktime(0,0,0,$arr[0],$arr[1],$arr[2]));
}
return $newarr;
}
function cmp2($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$third = date_to_timestamp($ArrayDates);
usort($third, "cmp2");
echo date('m/d/Y', $third[0]);
?>
This will sort the array of date in ascending order.
$date = array('23-02-2012','21-01-2014','11-01-2010','09-02-2001','01-01-2019');
function date_sort($a, $b) {
return strtotime($a) - strtotime($b);
}
usort($date, "date_sort");
print_r($date);
Output:-
Array (
[0] => 09-02-2001
[1] => 11-01-2010
[2] => 23-02-2012
[3] => 21-01-2014
[4] => 01-01-2019
)
I want to sort this array by year:
Array
(
[0] => data/pictures/alice/1980
[1] => data/pictures/alice/1985
[2] => data/pictures/bob/1981
[3] => data/pictures/bob/1985
[4] => data/pictures/bob/1987
[5] => data/pictures/bob/1989
)
Expected result:
Array
(
[0] => data/pictures/alice/1980
[1] => data/pictures/bob/1981
[2] => data/pictures/alice/1985
[3] => data/pictures/bob/1985
[4] => data/pictures/bob/1987
[5] => data/pictures/bob/1989
)
I've already tried different sort functions without success.
Example:
asort($paths, SORT_STRING | SORT_FLAG_CASE);
sort($path, SORT_NUMERIC);
Since it's a path just map the array through basename() and then sort based on that:
array_multisort(array_map('basename', $paths), SORT_ASC, $paths);
Try this
function cmp($a, $b) {
// if equal, don't do much
if ($a == $b) {
return 0;
}
$explodedA = explode('/', $a);
$explodedB = explode('/', $b);
$yearPartA = $explodedA[count($explodedA) - 1];
$yearPartB = $explodedB[count($explodedB) - 1];
if ($explodedPartA == $explodedPartB) { // compare full string
return ($a < $b) ? -1 : 1;
}
return ($yearPartA < $yearPartB) ? -1 : 1;
}
// actual sort of the array $path (e.g. the whole point)
usort($path, "cmp");
Consider, however that you'd probably be doing 'explode' several times for each array element and that it might be cheaper to work a bit on the array first. Not sure how big your array is... Do some testing.
$array = ['data/pictures/alice/1980','data/pictures/alice/1985','data/pictures/bob/1981','data/pictures/bob/1985','data/pictures/bob/1987','data/pictures/bob/1989'];
uasort($array, function($a,$b) {
$y1 = array_pop(explode('/', $a));
$y2 = array_pop(explode('/', $b));
if($y1===$y2) {
// if year the same use other criteria
if($a===$b) {
return 0;
}
return $a>$b?-1:1;
};
return $y1>$y2?-1:1;
});
Use usort and in the custom function explode the strings by "/" and compare the last parts of the arrays.
I have the following array
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
I would like to sort this array from longest ago to most recent date.
foreach ($dates as $date) {
$date = new DateTime($date);
// The logic I need
}
Could you help me out?
Edit
I would like to note that the date format can vary. To elaborate, I have dates in my database formatted as YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY and DD/MM/YYYY.
But as suggested below I can reformat the date and build a new array. So this will probably not be an issue.
The dates you have are in shortened ISO8601 format, i.e. YYYY-MM-DD.
These have the nice feature that the lexical sort order is the same as date order. So, just sort the array using the default sort function. It'll work.
When handling date strings inside code it's always a good idea to have ISO8601 be the canonical internal date format. Convert user-supplied to that as soon as possible, and if the user requires output to be in their own locale then defer that to as late as possible. Of course, using a "proper" date object is better still!
Just try to convert all date formats to time numbers.
<?php
$finalArray = array();
foreach ($datesInFormatA as $date) {
$finalArray[] = strtotime($date);
}
foreach ($datesInFormatB as $date) {
$finalArray[] = strtotime($date);
}
And for all of your date formats do this. Then you will have an array of numbers that you can sort them easily.
$finalArray = sort($finalArray);
You can convert with strtotime() to safely date-manipulating and then you can reorder the array:
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
$newArray = array();
foreach($dates as $value) {
$newArray[] = strtotime($value);
}
sort($newArray);
var_dump($newArray);
Use PHP sort function
<?php
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
sort($dates);
var_dump($dates);
Output:
array(9) {
[0]=>
string(10) "2015-01-07"
[1]=>
string(10) "2015-02-11"
[2]=>
string(10) "2015-02-13"
[3]=>
string(10) "2015-03-02"
[4]=>
string(10) "2015-04-21"
[5]=>
string(10) "2015-07-14"
[6]=>
string(10) "2015-08-18"
[7]=>
string(10) "2015-09-15"
[8]=>
string(10) "2015-11-26"
}
Remember, this works for 'Y-m-d' format. For other formats you need to convert to date format using strtotime() function and need to proceed. Something like this (standard formats):
function sortFunction( $a, $b ) {
return strtotime($a[0]) - strtotime($b[0]);
}
usort($dates, "sortFunction");
Dates in the m/d/y or d-m-y formats are disambiguated by looking at
the separator between the various components: if the separator is a
slash (/), then the American m/d/y is assumed; whereas if the
separator is a dash (-) or a dot (.), then the European d-m-y format
is assumed.
Try this quick sort algorithm.
What it does is, it compares the date as Unix Timestamp which starts from Jan 01 1970 (UTC)) and sort it and put into the array.
Converting to Unix Timestamp asures the ISO8601 date format.
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
function quick_sort($array)
{
// find array size
$length = count($array);
// base case test, if array of length 0 then just return array to caller
if($length <= 1){
return $array;
}
else{
// select an item to act as our pivot point, since list is unsorted first position is easiest
$pivot = $array[0];
// declare our two arrays to act as partitions
$left = $right = array();
// loop and compare each item in the array to the pivot value, place item in appropriate partition
for($i = 1; $i < count($array); $i++)
{
if(strtotime($array[$i]) < strtotime($pivot)){
$left[] = $array[$i];
}
else{
$right[] = $array[$i];
}
}
// use recursion to now sort the left and right lists
return array_merge(quick_sort($left), array($pivot), quick_sort($right));
}
}
$sorted = quick_sort($dates);
print_r($sorted);
// Output
Array
(
[0] 2015-01-07
[1] 2015-02-11
[2] 2015-02-13
[3] 2015-03-02
[4] 2015-04-21
[5] 2015-07-14
[6] 2015-08-18
[7] 2015-09-15
[8] 2015-11-26
)
I have one solution for you, hope this will help you to sort as this is working for me.
I recommend you to use usort() With a custom function:
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
function date_fun_compare($a, $b)
{
$t1 = strtotime($a['datetime']);
$t2 = strtotime($b['datetime']);
return $t1 - $t2;
}
usort($dates, 'date_fun_compare');
Hope this will help you.
php does not work well in format MM DD YYYY because of the confusion between day and month.
For your first and second condition YYYY-MM-DD or YYYY/MM/DD you can follow this solution:
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015-01-07',
'2015-02-11',
'2015-07-14',
'2015-03-02',
);
function date_sorter($a, $b)
{
$t1 = strtotime($a);
$t2 = strtotime($b);
return $t1 - $t2;
}
usort($dates, 'date_sorter');
// check the output
echo '<pre>'.print_r($dates,1).'</pre>'
OUTPUT:
Array
(
[0] => 2015-01-07
[1] => 2015-02-11
[2] => 2015-02-13
[3] => 2015-03-02
[4] => 2015-04-21
[5] => 2015-07-14
[6] => 2015-08-18
[7] => 2015-09-15
[8] => 2015-11-26
)
FYI: you can try changing - to /
If the format is like YYYY DD MM (whatever it is / or -) you can see the following solution:
Sample input:
$dates = array(
'13/02/2015',
'21/04/2015',
'18/08/2015',
'26/11/2015',
'15/09/2015',
'07/01/2015',
'11/02/2015',
'14/07/2015',
'02/03/2015',
);
Function:
function date_sorter($a, $b )
{
$da = DateTime::createFromFormat('d/m/Y', $a); // define date format d/m/Y
$db = DateTime::createFromFormat('d/m/Y', $b); // define date format d/m/Y
$t1 = strtotime($da->format('Y-m-d'));
$t2 = strtotime($db->format('Y-m-d'));
return $t1 - $t2;
}
usort($dates, 'date_sorter');
echo '<pre>'.print_r($dates,1).'</pre>';
Output:
Array
(
[0] => 07/01/2015
[1] => 11/02/2015
[2] => 13/02/2015
[3] => 02/03/2015
[4] => 21/04/2015
[5] => 14/07/2015
[6] => 18/08/2015
[7] => 15/09/2015
[8] => 26/11/2015
)
However, perhaps it will help you.
Well, since you mentioned that you have all your dates in the following formats: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY and DD/MM/YYYY
First you will need to convert them to a single format, lets use YYYY-MM-DD.
Then as already mentioned, you will just need to regular sort it.
Included how you could re format your strings, without having to create a date object per each just for sorting.
$dates = array(
'2015-02-13',
'2015-04-21',
'2015-08-18',
'2015-11-26',
'2015-09-15',
'2015/01/07',
'2015-02-11',
'2015/07/14',
'2015-03-02',
'08/01/2015',
'08-04-2015',
);
array_walk($dates, function(&$el){
if($el[4] !== '-' && $el[4] !== '/'){
// Ugly, I know, but is the fastest
$el = $el[6] . $el[7] .$el[8] . $el[9] . '-' . $el[3] . $el[4] . '-' . $el[0] . $el[1];
// Or just explode, revert array and implode
}elseif($el[4] !== '-'){
$el = str_replace('/', '-', $el);
}
});
sort($dates);
print_r($dates);
Will print:
Array
(
[0] => 2015-01-07
[1] => 2015-01-08
[2] => 2015-02-11
[3] => 2015-02-13
[4] => 2015-03-02
[5] => 2015-04-08
[6] => 2015-04-21
[7] => 2015-07-14
[8] => 2015-08-18
[9] => 2015-09-15
[10] => 2015-11-26
)
Want it to other way, just use rsort($dates) instead.
Depending on the format of your date (in your case is ok with Y-m-d) just perform a sort
sort($dates);
I am trying to sort the arrays (each containing 2 date values) in a multidimensional array. I was able to find a useful function which solves the question for one element, however I was unable to modify it for two.
PHP Sort a multidimensional array by element containing date
function date_compare($a, $b)
{
$t1 = strtotime($a['datetime']);
$t2 = strtotime($b['datetime']);
return $t1 - $t2;
}
usort($array, 'date_compare');
The problem at hand is sorting comments in which have a post time and an edit time. Essentially I want to sort them from newest to oldest (while keeping both values).
If this is not possible, let me know.
EDIT: Mockup
$array = array(
[0] => array(
[0] => "Aug:1:2012 12:00:pm", // post date
[1] => "Aug:28:2012 12:00:pm" // edit date
),
[1] => array(
[0] => "Aug:1:2012 12:00:pm",
[1] => "Aug:30:2012 12:00:pm"
)
[2] => array(
[0] => "Aug:29:2012 12:00:pm",
[1] => "Aug:1:2012 12:00:pm"
)
};
Should output: $array[1] first (because it has the highest date out of keys 1 & 2) then $array[2], then $array[0].
$array = array(
[0] => array(
[0] => "Aug:1:2012 12:00:pm",
[1] => "Aug:30:2012 12:00:pm" // highest
),
[1] => array(
[0] => "Aug:29:2012 12:00:pm", // next
[1] => "Aug:1:2012 12:00:pm"
)
[2] => array(
[0] => "Aug:1:2012 12:00:pm",
[1] => "Aug:28:2012 12:00:pm" // lowest
)
};
Your sort func needs to first work out which date is more recent - the post or edit date, then use that for the comparison.
function sort_arr($arr1, $arr2) {
$this_posted = strtotime($arr1[0]);
$this_edited = strtotime($arr1[1]);
$comparison_posted = strtotime($arr2[0]);
$comparison_edited = strtotime($arr2[1]);
$this_date = $this_posted > $this_edited ? $this_posted : $this_edited;
$comparison_date = $comparison_posted > $comparison_edited ? $comparison_posted : $comparison_edited;
return $this_date > $comparison_date;
}
$arr = array(
array("Aug:1:2009 12:00:pm", "Aug:2:2009 12:00:pm"),
array("Aug:1:2011 12:00:pm", "Jul:21:2012 12:00:pm"),
array("Aug:5:2011 12:00:pm", "Jan:21:2013 12:00:pm")
);
usort($arr, 'sort_arr');
I'm not sure if understood correctly but you mean you want sort your array base on column1 ("post date") and if these values are equal order is determined by column2. So, what you need is just fix your comparing function:
function date_compare($a, $b)
{
$t1 = strtotime($a['datetime']);
$t2 = strtotime($b['datetime']);
if ($t1 != $t2) {
return $t1 - $t2;
}
// if "post dates" are equal, compare "edit dates"
$t1 = strtotime($a['datetime2']);
$t2 = strtotime($b['datetime2']);
return $t1 - $t2;
}
edit:
ok, according to your comment, you just need to pick up max element from your array. So, this should work:
usort($array, function($a, $b) {
$t1 = max(strtotime($a[0]), strtotime($a[1]));
$t2 = max(strtotime($b[0]), strtotime($b[1]));
return $t1 - $t2;
});