I have an array of PHP DateTime objects:
$dates = [
new DateTime('2019-08-15'),
new DateTime('2019-08-19'),
new DateTime('2019-08-20')
];
What I would like to receive from this array is the average date, which in my calculation would be 2019-08-18.
Is there a simple way of doing this without breaking down the date parts for each item and finding the average of all of them and then splicing it back together?
Thank you!
Basically you have no choice other than to iterate over all the values and summing them (using timestamps is the most efficient way), taking the average and then converting that value back to a date:
echo date('Y-m-d', array_reduce($dates, function ($c, $d) {
return $c + $d->format('U');
}, 0) / count($dates));
An alternate way would be to find the difference between each of the dates and the first date in the array, and then take the average of those values and add it to the first date:
$days = 0;
foreach ($dates as $date) {
$days += $dates[0]->diff($date)->days;
}
$days = intdiv($days, count($dates));
$avg_date = (clone $dates[0])->modify("+$days days");
echo $avg_date->format('Y-m-d');
In both cases the output is:
2019-08-18
Demo on 3v4l.org
Related
How do I work out the average time from an array of times.
I have an array that looks like this :
('17:29:53','16:00:32')
And I wish to achieve the result 16:45:12 using PHP.
date('H:i:s', array_sum(array_map('strtotime', $array)) / count($array))
Untested solution typed on my phone, should work though.
$times = array('17:29:53','16:00:32');
$totaltime = '';
foreach($times as $time){
$timestamp = strtotime($time);
$totaltime += $timestamp;
}
$average_time = ($totaltime/count($times));
echo date('H:i:s',$average_time);
convert both using strtotime() function
add the value
divide by 2 (or how many items there in your array)
convert back to normal time format
Loop over all Entries and add times, converted to seconds
Divide by length of Array and convert back to hh:mm:ss
So I have an array of objects that looks like this:
credit_cards[[0] => {expiration_date: {year: "17", month: "04"}]
What I try to do is somethings like this:
$years = [];
$months = [];
$dates = [];
foreach ($clients->settings->credit_cards as $key => $value){
$years[] = $value->expiration_date->year;
$months[] = $value->expiration_date->month;
}
I need to loop through every credit card in that array and make an array $dates that should form a basic date by concatenating years and months. So in this case it should look like this: $dates = ['2017-04']. But I have no idea how to do this. Any help is welcomed and some explanation if you may so I can understand how to do this in the future.
You can just add the dates with a minor amount of work. create a parseable string that represents your Month / Year. Then put it in php's strtotime(). That integer representing seconds since the epoch is the 2nd argument to format the four digit date -dash- month that you are looking for.
$years[] = $value->expiration_date->year;
$months[] = $value->expiration_date->month);
$my = $value->expiration_date->month.'/'.$value->expiration_date->year;
$dates[] = date('Y-m', strtotime($my));
You're looking for the concatenate operator: . (More info here.) You can build a formatted date string and pass it to strtotime like WEBjuju's answer, or move directly to using the concatenation.
$years[] = $value->expiration_date->year;
$months[] = $value->expiration_date->month;
$dates[] = $value->expiration_date->year . '-' . $value->expiration_date->month;
I have an array with dates as keys and prices as values. Like this:
Array
(
[2016-11-11] => 25.05
[2016-11-12] => 25.05
[2016-11-13] => 25.05
[2016-11-14] => 25.05
...
)
Now i need to calculate the mean value of today - 1 till today - 8. Of course it should also calculating correctly if there is less than 8 entries.
I'm thinking of extracting the keys and filter for the values and put that all in for loop. But i bet there will be a better way. I am at least happy for an idea in which direction to start with. May you help me?
The "today" i defined like this:
date_default_timezone_set("Europe/Berlin");
$timestamp = time();
$today = date("Y-m-d",$timestamp);
edit:
The output should be like
$last_week_mean = "value" of key[today-1] + "value" of key [today-2]
+ ... / count(amount of key values in this range)
But i don't know how to build this query/filter - thing :)
You can use array_filter with ARRAY_FILTER_USE_KEY to get the specific date range you want. But after than, you don't need to use a loop to calculate the average. You can just use sum / count of the filtered array.
$d1 = date('Y-m-d', strtotime('8 days ago'));
$d2 = date('Y-m-d', strtotime('1 day ago'));
$range = array_filter($your_array, function($date_string) use ($d1, $d2) {
return $date_string >= $d1 && $date_string <= $d2;
}, ARRAY_FILTER_USE_KEY);
$average = array_sum($range) / count($range);
Also, just in case you're getting your initial array from a database, it would most likely be easier and more efficient to only select the dates you want to begin with.
Given today's date in the format dd-mm-yyyy
How would i find the next date from a string array with dates (of the same format) in the most efficient way.
The array has no order and it may contain dates prior to the given date.
Though I would like to have the soonest date close to the given date, but not form the past.
I have thought of first converting to a DateTime then loop it through keep in memory one variable holding the soonest date which is just compared ("<") with the next date.
Is there a faster/better way in php?
I suggest you use unix time (strtotime).
So loop through the array and create a new array with each date as unix time.
Give it a try I have not tested it but in (my) theory it should work.
foreach ($arr as $value) {
$new_arr[] = strtotime($value);
}
$nearest = closest($new_arr[], strtotime(time());
Echo date("d-m-Y",$nearest);
function closest($new_arr, $today) {
sort($new_arr);
foreach ($new_arr as $a) {
if ($a >= $today) return $a;
}
return end($new_arr);
}
I have a situation whereby a series of 15 dates have been created, currently in UNIX timestamps.
Another variable <?php $dateidate = date(strtotime('+20 days')); ?>
The objective is to find the smallest of the 15 other dates that is greater > than $dateidate and display in the format of 'd-m-Y'
Once we've done that is there a way to get the second smallest of the 15 other dates that is greater > than $dateidate and display in the format of 'd-m-Y'.
So, you have 15 dates which are UNIX timestamps. Useful.
Ok, here's what you can do to do it easily:
$datearray = array(timestamp1,timestamp2,etc.) // an array of timestamps
$dateidate = time() + 1728000; //current time + 20 days worth of seconds (20 * 24 * 60 * 60)
foreach($datearray as $key => $date)
{
if($date < $dateidate)
{
unset $datearray[$key]; //Remove timestamp from original array if less than $dateidate
}
}
$earliestdate = min($datearray);
//min returns the least of the values in the array, opposite of max, which you could use to find the latest date in the array
$date = date('d-m-Y',$earliestdate);
strtotime generates a timestamp.
instead of this:
<?php $dateidate = date(strtotime('+20 days')); ?>
do this:
<?php $dateidate = strtotime('+20 days'); ?>
Put all timestamps into an array with special keys so you can distinguish which one is your pivot.
Sort that array and do what you need to do with the sorted array.
This solution filters the $dates array which stores the timestamps using an anonymous function, so in the $shorterOnes array you will have all the timestamps that are bigger than $dateidate.
Then the array is sorted, the first one will be smallest and so on.
$dateidate=strtotime('+20 days');
$dates=array(/*timestamps*/);
$shorterOnes=array_filter($dates, function ($v) use ($dateidate) {
return $v>$dateidate;
});
sort($shorterOnes);
echo date('d-m-Y', $shorterOnes[0]);
echo date('d-m-Y', $shorterOnes[1]);
Anonymous functions only work from PHP 5.3. Lower than that, you need to use create_function().