get average of given dates in php - php

I try to get an average of given dates but I failed when dates are from two different years. I need something like this
given dates:
2017-06-1
2017-06-3
2017-06-4
2017-06-3
2017-06-5
output : 2017-06-4
this is my code:
$total = 0;
foreach ($dates as $date) {
$total+= date('z', strtotime($date))+1;
}
$avg_day = $total/sizeof($dates);
$date = DateTime::createFromFormat('z Y', $avg_day . ' ' . date("Y"));
but my code is not working for
given dates:
2016-12-29
2016-12-31
2017-01-1
2017-01-5
2017-01-3

You can work with timestamp of the date and use avg() method of the Illuminate\Support\Collection
$dates = [
'2016-12-29', '2016-12-31', '2017-01-1', '2017-01-5', '2017-01-3'
];
$dateCollection = collect();
foreach($dates as $date){
$dateCollection->push((new \DateTime($date))->getTimestamp());
}
$averageTimestamp = $dateCollection->avg(); //timestamp value
$averageDate = date('Y-m-d', $average);
Or using Carbon package:
$dateCollection->push(Carbon::parse($date)->timestamp);
...
$averageDate = Carbon::createFromTimestamp($average)->toDateString();

Your code is not working for your base dates. The correct output for
2017-06-1 2017-06-3 2017-06-4 2017-06-3 2017-06-5
is
2017-06-03
According to OpenOffice calc, and overall logic (a date is represented by epoch number)
Check out this script
$dates = ['2017-06-1 ', '2017-06-3', '2017-06-4', '2017-06-3', '2017-06-5'];
$dates = array_map('strtotime', $dates);
$average = date('Y-m-d', array_sum($dates) / count($dates)); // 2017-06-03 (1496490480)
echo $average;
Keep simple tasks simple

I think you have problem with averaging year. So, You can do this to get average.
Just an algorithm:
Find smallest date among your dates at first as $smallest
Initiate a variable $total = 0;
Add difference of each date in days with smallest date.
Find average from total.
Add this total to smallest date.
Here, You have smallest as $smallest = '2016-12-29'
$total = 0;
$dates = ['2016-12-29', '2016-12-31', '2017-01-1', '2017-01-5', '2017-01-3'];
$smallest = min($dates);
$smallest = Carbon::parse($smallest);
foreach($dates as $date){
$d = Carbon::parse($date);
$total = $total+$smallest->diffInDays($d);
}
$average_day = $total/sizeof($dates);
$average_date = $smallest->addDays($average_day);
Hope, This might help you.

Related

I want to calculate this time Laravel

$array = [ '00:09:45', '00:50:05', '00:01:05', ]
I tried this calculating time but it is not working.
I understand that by calculate he meant addition.
(Nuances related to translation). Below is an example function in Laravel that adds these times from an array. You should use Carbon for this purpose.
use Carbon\Carbon;
function addTimes($times) {
$totalTime = Carbon::createFromTime(0, 0, 0);
foreach ($times as $time) {
$time = Carbon::createFromFormat('H:i:s', $time);
$totalTime->addSeconds($time->secondsSinceMidnight());
}
return $totalTime;
}
$times = [ '00:09:45', '00:50:05', '00:01:05', ];
$totalTime = addTimes($times);
echo $totalTime->format('H:i:s');
I believe you want sum the durations of time. We can transform it in a collection and reduce it by adding the times.
use Carbon/Carbon;
$array = collect(['12:09:45', '11:50:05', '07:01:05']);
$total = $array->reduce(function ($time, $timeNext){
$carbonTimeNext = new Carbon($timeNext);
$time->addHours($carbonTimeNext->format('H'))
->addMinutes($carbonTimeNext->format('i'))
->addSeconds($carbonTimeNext->format('s'));
return $time;
}, new Carbon('00:00:00'));
echo $total->shortAbsoluteDiffForHumans(new Carbon('00:00:00'), 6);
//output: 1d 7h 55s
Summing times can be done using Carbon like so (less is more):
use Carbon\Carbon;
$times = ['00:09:45', '00:50:05', '00:01:05'];
$time = Carbon::createFromTimestamp(array_reduce($times, function($sum, $item) {
return $sum + Carbon::createFromTimestamp(0)->setTimeFromTimeString($item)->timestamp;
}));
Note: the resulting $time variable is a Carbon date from unix time = 0 with the times added from your array.
The sum of seconds from your array can thus be retrieved using the timestamp property, which is the amount of seconds since the start of the unix epoch:
$sumSeconds = $time->timestamp;
// 3655
Displaying it as a string goes as follows:
use Carbon\CarbonInterface;
$str = $time->diffForHumans(Carbon::createFromTimestamp(0), CarbonInterface::DIFF_ABSOLUTE, false, 2);
// "1 hour 55 seconds"

count occurrence of date (e.g 14th) between two dates

How can I count occurrences of 14th of a month between two dates
For example between 07.05.2018 and 04.07.2018
I have 2 occurrences of the 14th
Try this. Note that I've changed your date format, but you can just do a createFromFormat if you're really keen on your own format.
$startDate = new DateTime('2018-05-07');
$endDate = new DateTime('2018-07-04');
$dateInterval = new DateInterval('P1D');
$datePeriod = new DatePeriod($startDate, $dateInterval, $endDate);
$fourteenths = [];
foreach ($datePeriod as $dt) {
if ($dt->format('d') == '14') { // Note this is loosely checked!
$fourteenths[] = $dt->format('Y-m-d');
}
}
echo count($fourteenths) . PHP_EOL;
var_dump($fourteenths);
See it in action here: https://3v4l.org/vPZZ0
EDIT
This is probably not an optimal solution as you loop through every day in the date period and check whether it's the fourteenth. Probably easier is to modify the start date up to the next 14th and then check with an interval of P1M.
You don't need to loop at all.
Here's a solution that does not loop at all and uses the less memory and performance hungry date opposed to DateTime.
$start = "2018-05-07";
$end = "2018-07-04";
$times = 0;
// Check if first and last month in the range has a 14th.
if(date("d", strtotime($start)) <= 14) $times++;
if(date("d", strtotime($end)) >= 14) $times++;
// Create an array with the months between start and end
$months = range(strtotime($start . "+1 month"), strtotime($end . "-1 month"), 86400*30);
// Add the count of the months
$times += count($months);
echo $times; // 2
https://3v4l.org/RevLg

Find number of days ( comma separated ) between two dates in php

I have comma separated days(1,3,5,6) and i want to count number of days between two days.
I have done this as below.
$days=$model->days; // comma saperated days
$days=explode(',',$days); // converting days into array
$count=0;
$start_date = $model->activity_start_date; // i.e. 2018-03-27
$end_date = date('Y-m-d');
while(strtotime($start_date) <= strtotime($end_date)){
if(in_array(date("N",strtotime($start_date)),$days)){ // check for day no
$count++;
}
$start_date = date ("Y-m-d", strtotime("+1 day", strtotime($start_date)));
}
This code is working fine. But the problem is if difference between two date will be year or more than a year than it loop 365 times or more.
Is there any way to reduce execution time to count days. Or it is possible to get counts of days using mysql query.
Real Scenario : I have one event which have start date and it occurs multiple in week(i.e. Monday and Wednesday ) and i want to find how many times event occur from start date to now. If start date is 2018-04-9 and today is 2018-05-9 than count will be 9
This requires no looping.
I find how many weeks between start and end and multiply full weeks (in your example 16,17,18) with count of days.
Then I find how many days there is in first week (15) that is higher than or equal to daynumber of startday.
Then the opposit for week 19.
$days="1,3"; // comma saperated days
$days=explode(',',$days); // converting days into array
$count=0;
$start_date = "2018-04-09";
$end_date = "2018-05-09";
// calculate number of weeks between start and end date
$yearW = floor(((strtotime($end_date) - strtotime($start_date)) / 86400)/7);
if($yearW >0) $count = ($yearW -1)*count($days); //full weeks multiplied with count of event days
$startday = date("N", strtotime($start_date));
$endday = date("N", strtotime($end_date));
//find numer of event days in first week (less than or equal to $startday)
$count += count(array_filter($days,function ($value) use($startday) {return ($value >= $startday);}));
//find numer of event days in last week (less than $endday)
$count += count(array_filter($days,function ($value) use($endday) {return ($value < $endday);}));
echo $count; // 9
https://3v4l.org/9kupt
Added $yearW to hold year weeks
Here, I have a code I have used previously in a project. It is used to find the distance between date from today.
public function diffFromToday($date){
$today = date('jS F, Y');
$today = str_replace(',','',$today);
$today=date_create($today);
$today = date_format($today,"Y-m-j");
$date = str_replace(',','',$date);
$date=date_create($date);
$date = date_format($date,"Y-m-j");
$today=date_create($today);
$date=date_create($date);
$diff=date_diff($today,$date);
$result = $diff->format("%R%a");
$result = str_replace('+','',$result);
return $result;
}
You can use this function according to your requirement. Date format used in this function is 'jS F, Y' DO not be confused and use your own format to convert.
$start_date = date_create('2018-03-27');
$end_date = date_create('2018-04-27');
$t = ceil(abs($endDate- $start_date) / 86400);
echo date_diff($start_date, $end_date)->format('%a');
Output with like this
396
Could you not use the date->diff function to get the values you can directly use like -5 or 5?
$diffInDays = (int)$dDiff->format("%r%a");
Here is something for format parameter descriptions if it could be helpful to you.
You may use tplaner/when library for this:
$days = str_replace(
['1', '2', '3', '4', '5', '6', '0', '7'],
['mo', 'tu', 'sa', 'th', 'fr', 'sa', 'su', 'su'],
'1,3'
);
$when = new When();
$when->rangeLimit = 1000;
$occurrences = $when->startDate(new DateTime('2018-04-9'))
->freq('daily')
->byday('mo,we')
->getOccurrencesBetween(new DateTime('2018-04-9'), new DateTime('2018-05-9'));
echo count($occurrences);

how may days are between two dates in specific year

I'm solving following task>
I have two dates - $start and $end and target year as $year.
dates are php DateTime objects, year is string.
add:dates comes acutaly from MySql field from this format 2017-02-01 15:00:00 ...
add2: if end date is null, I use todays date ...
I need to figure out how many days are between these two dates for specific year.
Also I need to round it for whole days, even if one minute in day should be counted as whole day ...
I can solve it by many many following ifs.
Expected results for values I used in example are
2016 is 0 days
2017 is 31 days
2018 is 32 days
2019 is 0 days
But are there any elegant php functions which can help me with this ?
What I did it seems to be wrong way and giving bad results - seems it counts full days only ...
Please see my code here >
<?php
$diff = True;
$start = DateTime::createFromFormat('Y-m-d H:i:s','2017-12-01 23:05:00');
$end = DateTime::createFromFormat('Y-m-d H:i:s','2017-12-03 00:05:00');
$year = '2017';
// start date
if ($start->format('Y')<$year)
{
$newstart = new DateTime('first day of January '. $year);
}
if ($start->format('Y')==$year)
{
$newstart = $start;
}
if ($start->format('Y')>$year)
{
$result = 0;
$diff = False;
}
// end date
if ($end->format('Y')>$year)
{
$newend = new DateTime('last day of December '. $year);
}
if ($end->format('Y')==$year)
{
$newend = $end;
}
if ($end->format('Y')<$year)
{
$result = 0;
$diff = False;
}
// count if diff is applicable
if ($diff)
{
$result = $newend->diff($newstart)->format("%a");
}
echo $result;
?>
But are there any elegant php functions which can help me with this ?
Read about DateTime::diff(). It returns a DateInterval object that contains the number of days (in $days) and by inspecting the values of $h, $i and $s you can tell if you have to increment it to round the result. You can also use min() and max() to crop the time interval to the desired year.
function getDays(DateTimeInterface $start, DateTimeInterface $end, $year)
{
// Extend the start date and end date to include the entire day
$s = clone $start; // Don't modify $start and $end, use duplicates
$s->setTime(0, 0, 0);
$e = clone $end;
$e->setTime(0, 0, 0)->add(new DateInterval('P1D')); // start of the next day
// Crop the input interval to the desired year
$s = min($s, new DateTime("$year-01-01 00:00:00"));
$year ++;
$e = max(new DateTime("$year-01-01 00:00:00"), $end); // start of the next year
if ($e <= $s) {
// The input interval does not span across the desired year
return 0;
}
// Compute the difference and return the number of days
$diff = $e->diff($s);
return $diff->days;
}
$d1 = strtotime('2017-05-15');
$d2 = strtotime('2017-05-31');
$div = 24 * 3600;
echo abs(($d2 - $d1) / $div); // 16 days
Just make sure and ONLY have the date part and you shouldn't have to deal with rounding.

PHP: Split unix timestamp range into 5 chuncks

I have a requirement where I need to extract 5 points from a Unix time stamp or PHP time stamp range.
For Example,
From 2014-06-26 07:53:26 to 2014-06-27 07:52:46.
I need five points from these two dates in exact or approximate intervals, to chart using pChart.
Currently My Code is
$diff = $mintime->diff($maxtime);
$range = max($timestamps) - min($timestamps);
$cnt = count($timestamps);
$temp = ceil($range * (20/100));
for($i=0;$i<$cnt;$i++)
{
if($i%($cnt/5) == 0)
$point[$i] = gmdate("Y-m-d H:i:s",min($timestamps) + $temp * ($i+1));
else
$point[$i] = null;
}
But My Code returns erratic values. I know the problem is with the temp variable. Help me solve this.
Thanks
Try this:
$from = '2014-06-26 07:53:26';
$to = '2014-06-27 07:52:46';
$diff_stamp = strtotime($to) - strtotime($from);
$range = range(strtotime($from), strtotime($to), $diff_stamp/4);
Here, $range is an array of timestamps. To convert each back to a date, you could use array_map:
$range = array_map(function($a){return date('Y-m-d H:i:s', $a);}, $range);
See Demo Updated
Resources:
strtotime(), range(), array_map()
$splitter=($timestamp1-$timestamp2);
$timestamp_between=array();
for($i=0;$i<5;$i++) $timestamp_between[]=$timestamp1+($i*$splitter);
print_r($timestamp_between);

Categories