How can I separate from and to dates from dates array? - php

I have an array, which has only one month dates.
$dates =array (
'2018-10-15',
'2018-10-16',
'2018-10-17',
'2018-10-13',
'2018-10-19',
'2018-10-10',
'2018-10-11',
'2018-10-12',
'2018-10-22',
'2018-10-23',
'2018-10-29',
);
And script below
usort($dates,function($a,$b){
return strtotime($a) - strtotime($b);
});
$consecutive_added_set = [];
$consecutive_array = [];
$temp = [];
$temp[] = date('Y-m-d',strtotime($dates[0]));
for($i=1;$i<count($dates);++$i){
if(strtotime($dates[$i]) - strtotime($dates[$i - 1]) === 86400){ // 1 day gap(86400 seconds)
$temp[] = date('Y-m-d',strtotime($dates[$i]));
$consecutive_added_set[$dates[$i-1]] = true;
$consecutive_added_set[$dates[$i]] = true;
}else{
if(count($temp) > 1){
$consecutive_array[] = $temp;
}
$temp = [];
$temp[] = date('Y-m-d',strtotime($dates[$i]));
}
}
if(count($temp) > 1){ // the last consecutiveness match of dates as well(corner case)
$consecutive_array[] = $temp;
}
$conseq[] = []; // reset the array structure
$conseq['consecutive'] = $consecutive_array;
$conseq['consecutive_count'] = count($consecutive_array);
$conseq['non_consecutive'] = [];
foreach($dates as $current_date){
if(!isset($consecutive_added_set[$current_date])){ // skip all dates which were d for consecutiveness
$conseq['non_consecutive'][] = date('Y-m-d',strtotime($current_date));
}
}
Which is sorting and separating consecutive and non-consective dates. Currently in consecutive array it is showing all dates by group. But I just would like to show from and to dates. Here is output of above script
Array
(
[0] => Array
(
)
[consecutive] => Array
(
[0] => Array
(
[0] => 2018-10-10
[1] => 2018-10-11
[2] => 2018-10-12
[3] => 2018-10-13
)
[1] => Array
(
[0] => 2018-10-15
[1] => 2018-10-16
[2] => 2018-10-17
)
[2] => Array
(
[0] => 2018-10-22
[1] => 2018-10-23
)
)
[consecutive_count] => 3
[non_consecutive] => Array
(
[0] => 2018-10-19
[1] => 2018-10-29
)
)
My desired output
[consecutive] => Array
(
['dates1'] => Array
(
[0] => 2018-10-10
[3] => 2018-10-13
)
['dates2'] => Array
(
[0] => 2018-10-15
[2] => 2018-10-17
)
['dates3'] => Array
(
[0] => 2018-10-22
[1] => 2018-10-23
)
)
I have tried a lot to do it.

A quick workaround would be to get the first and last item in the array.
$consecutive_array = array_map(function($e){
if(!is_array($e)){
return $e;
}
$last = end($e);
return [reset($e), $last];
}, $consecutive_array);
Or as suggested in the comments use min() max() functions.
$consecutive_array = array_map(function($e){
if(!is_array($e)){
return $e;
}
return [min($e), max($e)];
}, $consecutive_array);

Important: don't rely on strtodate of a day being exactly 86400 seconds less than the strtodate of the next day - depending on the locale of the server, there will be daylight saving, which can mess this up!
In cases like this, I tend to compare strtodate('+1 day',$timestampOfDay1) to strtodate($timestampOfDay2) - this will include daylight saving.
Here's how I would do it:
//the dates
$dates =array (
'2018-10-15',
'2018-10-16',
'2018-10-17',
'2018-10-13',
'2018-10-19',
'2018-10-10',
'2018-10-11',
'2018-10-12',
'2018-10-22',
'2018-10-23',
'2018-10-29',
);
//call the function
$result = getConsecutive($dates);
//output
var_dump($result);
function getConsecutive($dates) {
sort($dates);
$result = [
'consecutive' => [],
'consecutive_count'=>0,
'non_consecutive' => []
];
$currentStart = null;
$currentTimestamp = null;
for ($i=0; $i<count($dates); $i++) {
$timestamp = strtotime($dates[$i]);
if ($currentStart == null) {
//first timestamp - set it as start & current
$currentStart = $timestamp;
$currentTimestamp = $timestamp;
} else if (strtotime('+1 day',$currentTimestamp) == $timestamp) {
//consecutive - keep waiting for a non-consecutive
$currentTimestamp = $timestamp;
} else {
if ($currentTimestamp == $currentStart) {
//we just got one
$result['non_consecutive'][] = date('Y-m-d',$currentTimestamp);
} else {
//we just got more then one, so they were consecutive
$result['consecutive']['dates'.(count($result['consecutive'])+1)] = [
date('Y-m-d',$currentStart),
date('Y-m-d',$currentTimestamp)
];
}
$currentStart = $timestamp;
$currentTimestamp = $timestamp;
}
}
//process the last timestamp
if ($currentTimestamp == $currentStart) {
//we just got one
$result['non_consecutive'][] = date('Y-m-d',$currentTimestamp);
} else {
//we just got more then one, so they were consecutive
$result['consecutive']['dates'.(count($result['consecutive'])+1)] = [
date('Y-m-d',$currentStart),
date('Y-m-d',$currentTimestamp)
];
}
$result['consecutive_count'] = count($result['consecutive']);
return $result;
}

Related

How to add days interval dynamically between date range

I want to print all dates between given date range within their interval.But i am adding 2 days if there is any saturday, and adding 1 day more if any sunday between them.
For ex -
1) 30/07/2018 is my start date.than add 5 days.
2) 06/08/2018 is the second coming date,than add 5 days to 06/08/2018,So it may be 11/08/2018 but 11/08 and 12/08 are sat and sunday,so add two days,so next date will be
3) 13/08/2018 is my third date like wise... 13/08/2018 + 5days = 18/08/2018 but 18/08 and 19/08 is sat and sunday, so add 2 days more.
4) 20/08/2018 is my fourth date....like wise.
5) 27/08/2018 is my last date bcoz its my end date.
6) Finish
Plz help me to achieve my expected output
Expected output
Array
(
[0] => Array
(
[month_year] => 30/07/2018
)
[1] => Array
(
[month_year] => 06/08/2018
)
[2] => Array
(
[month_year] => 13/08/2018
)
[3] => Array
(
[month_year] => 20/08/2018
)
[4] => Array
(
[month_year] => 27/08/2018
)
)
Below is my code
public function testdate(){
$date_from = new \DateTime("7/30/2018");
$date_to = new \DateTime("8/27/2018");
$interval = new \DateInterval("P5D");
$dates = new \DatePeriod($date_from, $interval, $date_to);
$out = array();
if (!empty($dates)) {
foreach($dates as $dt) {
$curre = $dt->format('D');
if($curre == 'Sat'){
$dt->add(new \DateInterval('P2D'));
}
if($curre == 'Sun'){
$dt->add(new \DateInterval('P1D'));
}
$out[] = array(
'month_year' => $dt->format('d/m/Y')
);
//print_r($out);exit;
}
}
'<pre>';
//$out = array_reverse($out);
print_r($out);
'</pre>';
exit;
}
I would rather resign from using \DatePeriod if there are some non-standard requirements, and go with do...while loop. Something like this:
function dates_between(\DateTime $date_from, \DateTime $date_to) {
// always reset the time when working only with dates
$date_from->setTime(0, 0);
$date_to->setTime(0, 0);
$dates_between = [];
$current_dt = $date_from;
do {
$dates_between[] = [
'month_year' => $current_dt->format('d/m/Y'),
];
$current_dt->add(new \DateInterval('P5D'));
if ($current_dt->format('D') === 'Sat') {
$current_dt->add(new \DateInterval('P2D'));
}
elseif ($current_dt->format('D') === 'Sun') {
$current_dt->add(new \DateInterval('P1D'));
}
} while ($current_dt <= $date_to);
return $dates_between;
}
print_r(
dates_between(
new \DateTime('7/30/2018'),
new \DateTime('8/27/2018')
)
);

Not displaying the last value for ksort in php

I have this sorting algorithm to sort the $days in reference to $daysOfWeek but I'm not sure why the last value is not being include to my array. Here is the code below
#default array
$daysOfWeek = array('M','T','W','TH','F');
#your array
$days = array('T','W','TH','','');
#create a new array with key association property
$daysAux = array();
foreach($days as $k=>$v) {
$key = array_search($v, $daysOfWeek);
if($key !== FALSE) {
$daysAux[$key] = $v;
}
else
$daysAux[$key] = '';
}
# array before sort
echo '<pre/>';print_r($daysAux);
ksort($daysAux);
$days = $daysAux;
#final result
echo '<pre/>';print_r($days);
#output
Array
(
[1] => T
[2] => W
[3] => TH
[0] =>
)
Array
(
[0] =>
[1] => T
[2] => W
[3] => TH
)
EXPECTED OUTPUT:
Array
(
[0] =>
[1] => T
[2] => W
[3] => TH
[4] =>
)
your code code should say $daysAux[$k] = instead of $daysAux[$key] =
beacuse otherwise when $key is false it will just overwrite the same entry instead of creating a new one
also need to swap days and daysOfWeek in the loop.
#default array
$daysOfWeek = array('M','T','W','TH','F');
#your array
$days = array('T','W','TH','','');
#create a new array with key association property
$daysAux = array();
foreach($days as $k=>$v) {
$key = array_search($v, $daysOfWeek);
if($key !== FALSE) {
$daysAux[$key] = $v;
}
else
$daysAux[$key] = '';
}
# array before sort
echo '<pre/>';print_r($daysAux);
ksort($daysAux);
$days = $daysAux;
#final result
echo '<pre/>';print_r($days);

Adding elements to an Array using a special loop for iteration

Supposing I have an Array with x elements. I would like to loop through this Array in "tens" and add a run-Time variable. This means that each set of 10 Arrays will have a unique run-time. I am using the code below:
$time = '00:00:00';
$k = 0;
for ($i = 0; $i < count($agnt_arr); $i+=10) {
$temp = strtotime("+$k minutes", strtotime($time));
$runTime = date('H:i', $temp);
array_push($agnt_arr[$i], $runTime);
$k+=4;
}
Where $agnt_arr is an Array with the following structure :
Array
(
[0] => Array
(
[name] => User.One
[email] => User.One#mail.com
)
[1] => Array
(
[name] => User.Two
[email] => User.Two#mail.com
)
[2] => Array
(
[name] => User.Three
[email] => User.Three#mail.com
)
)
The problem I'm having is the run times are only added to the 10th element which is expected But I would like elements 0-9 to have the same run time and 10-20 etc. How would I achieve something like this??
Probably easier like this always adding runtime but updating it for each 10:
$time = '00:00:00';
foreach($agent_arr as $key => $value) {
if($key % 10 === 0) {
$temp = strtotime("+$k minutes", strtotime($time));
$runTime = date('H:i', $temp);
}
$agent_arr[$key]['runtime'] = $runTime;
}
Here's my overcomplicated solution(and probably unnecessary):
$new_array = array();
foreach(array_chunk($array, 10 /* Your leap number would go here */) as $k => $v)
{
array_walk($v, function($value, $key) use (&$new_array){
$value['time'] = $time;
$new_array[] = $value;
});
}

Adding missing dates for 1 week back from now

I am trying to add the missing dates to this array for 1 week back from now.
This is an example array I have;
Array
(
[0] => Array
(
[date] => 2013-11-25
[members] => 2
)
[1] => Array
(
[date] => 2013-11-27
[members] => 1
)
)
This could have any dates in. I tried things like this, but I can see logically It doesn't work, but I cannot figure out a way.
$date_range = array();
$temp = array();
for ($i=0; $i<7; $i++)
{
$date = date("Y-m-d", strtotime($i." days ago"));
foreach($new_members as $members) {
if(!in_array($date, $members)) {
$temp['date'] = $date;
$temp['members'] = 0;
$new_members[] = array_merge($temp);
}
}
}
Solution provided by Dainis doesn't work for me, it's messing up the members and date.
Here is my solution:
<?php
$new_members = array ( array("date"=>"2013-11-25", "members" => 2), array("date"=>"2013-11-27", "members" => 2));
for ($i=0; $i<7; $i++)
{
$date = date("Y-m-d", strtotime($i." days ago"));
$found = false;
foreach($new_members as $members) {
if(array_search($date, $members) !== false) {
$found = true;
}
}
if(!$found) {
$new_members[] = array ("date" => $date, "members" => 0);
}
}
foreach($new_members as $nm) {
var_dump($nm);
}
?>
Instead of:
$temp['date'] = $date;
$temp['members'] = 0;
$new_members[] = array_merge($temp);
just do it like this:
$new_members[$i]['date'] = $date;
if ( !$new_members[$i]['members'] ) $new_members[$i]['members'] = 0;
After that you can sort it after ['date'] value and get a nice looking array.

How to split an array after that to update it and make a new array

I have this array
$test = $_POST['test'];
print_r($test);
Array
(
[0] => Array
(
[id] => 26629
[timestamp] => 1332273712
)
[1] => Array
(
[id] => 26628
[timestamp] => 1332243526
)
[2] => Array
(
[id] => 26627
[timestamp] => 1332237777
)
I want to get timestamp value and using a funciton to change it to something like 5 sec ago,4 hours ago and so on. The function is the easy part i'm just goin to use time() - timestamp..
Then when i get the new value have to make a new array with them that is going to content something like that
Array
(
[0] => Array
(
[id] => 26629
[content] => 5 sec ago
)
[1] => Array
(
[id] => 26628
[content] => 4 hours ago
)
[2] => Array
(
[id] => 26627
[content] => 1 hour ago
)
Probably i have to use foreach but i dont know how :(
You can use array_walk_recursive().
Your could could look like this:
//Make a copy of the array first, then operate on it, so that the final result is a seperate array.
$final = $test;
function transformTime(&$item, $key){
if($key == "timestamp"){
//Do something to $item
}
}
array_walk_recursive($final, 'transformTime');
//Convert to JSON for XHR:
$result = json_encode($final);
Code I am testing with:
<?php
$test = array(
array('id' => 26629,
'timestamp' => 1332273712),
array('id' => 26628,
'timestamp' => 1332243526),
array('id' => 26629,
'timestamp' => 1332273712),
array('id' => 26629,
'timestamp' => 1332273712),
);
var_dump($test);
$final = $test;
function transformTime(&$item, $key){
if($key == "timestamp"){
$item = $item + 5; //Obviously you need to convert the timestamp to something friendly here.
}
}
array_walk_recursive($final, 'transformTime');
var_dump($final);
Handling array
$arr = array
(
0 => array
(
'id' => 26629,
'content' => '5 sec ago',
),
1 => array
(
'id' => 26628,
'content' => '4 hours ago',
),
2 => array
(
'id' => 26627,
'content' => '1 hour ago',
)
);
foreach($arr as $arr1)
{
foreach($arr1 as $key=>$val)
{
echo $val.'<br />';
}
}
Find ago time pass time to it
function agoWord( $value )
{
if(isset ($value))
{
if(time() < strtotime($value))
{
$agoWord = "away";
}
else
{
$agoWord = "ago";
}
return $agoWord;
}
else
{
return 'Time not set for display.';
}
}
Function to calculate time differnce
function timeDiff($value)
{
if(isset ($value))
{
$ago = abs(time() - strtotime($value));
if($ago < 60)
{
$span = $ago;
return ($span != 1) ? $span." seconds" : " a second";
}
if($ago < 3600)
{
$span = round($ago/60);
return ($span != 1) ? $span." minute" : " one minute";
}
if($ago < 86400)
{
$span = round($ago/3600);
return ($span != 1) ? $span." hours" : " one hours";
}
if($ago < 2592000) // 86400*30 (Month)
{
$span = round($ago/86400);
return ($span != 1) ? $span." days" : " one day";
}
if($ago < 31536000) // 86400*365 (time<Year)
{
$span = round($ago/2592000);
return ($span != 1) ? $span." months" : " one month";
}
if($ago >= 31536000) //86400*365 (time>=Year)
{
$span = round($ago/31536000);
return ($span != 1) ? $span." years" : " one year";
}
}
else
{
return 'error';
}
}
foreach ($test as $key => $value) {
$test[$key]['content'] = get_timeago($value['timestamp']);
}
Copy get_timeago function from Here.

Categories