$a = array('2016-05-06', '2016-05-08', '2016-05-20', '2016-05-23');
foreach($a as $key => $value){
$dateFrom = $value //2016-05-06 Then 2016-05-20
$dateTo = $value //2016-05-08 Then 2016-05-23
function range($dateFrom, $dateTo);
} //in the second loop get the others 2 like above
The point is to pass first and last date and make a range
in the end get an array like this
Array
(
[0] => 2016-05-06
[1] => 2016-05-07
[2] => 2016-05-08
[3] => 2016-05-20
[4] => 2016-05-21
[5] => 2016-05-22
[6] => 2016-05-23
)
i got the first array with this, now the problem is being with the range using 4 dates
foreach(array_slice($dates, 2) as $key => $value){
$a[] .= $datas[$key];
if($key == 0){
$a[] .= $value;
} else {
$a[] .= $value;
}
}
One way to do this using DatePeriods:
$ranges = array_chunk($dates, 2); // Divide the array into groups of two
$interval = new DateInterval('P1D'); // Define an interval of one day
foreach ($ranges as $range) {
// Create DateTime objects for the start and end dates
$start = new DateTime($range[0]);
$end = new DateTime($range[1]);
$end->add($interval);
// Create a new DatePeriod object using the start and end DateTime objects
$period = new DatePeriod($start, $interval, $end);
// Iterate over the DatePeriod to fill your result array
foreach ($period as $date) {
$result[] = $date->format('Y-m-d');
}
}
Yes... it is possible and here is what i imagine you want:
<?php
$a = array('2016-05-06', '2016-05-08', '2016-05-20', '2016-05-23');
$arrDuos = array();
$arrTempRange = array();
foreach($a as $intKey=>$dateVal){
$arrTempRange[] = $dateVal;
if($intKey != 0 && $intKey%2){
$arrDuos[] = $arrTempRange;
$arrTempRange = array();
}
}
$arrArrangedDate = array();
foreach($arrDuos as $intKey=>$arrDateRange){
$startDate = $arrDateRange[0];
$endDate = $arrDateRange[1];
$dateDiff = date_diff( date_create($endDate), date_create($startDate) )->days;
for($i = 0; $i<=$dateDiff; $i++){
$incrementedDate = strtotime($startDate) + (60*60*24*$i);
$arrArrangedDate[] = date("Y-m-d", $incrementedDate);
}
}
// MANUALLY APPEND THE LAST ELEMENT OF THE ARRAY TO THE
// RESULTANT ARRAY IF THE ARRAY LENGTH IS ODD LIKE SO:
if(count($a)%2){
$arrArrangedDate[] = end($a);
}
var_dump($arrArrangedDate);
Dumps:
array (size=7)
0 => string '2016-05-06' (length=10)
1 => string '2016-05-07' (length=10)
2 => string '2016-05-08' (length=10)
3 => string '2016-05-20' (length=10)
4 => string '2016-05-21' (length=10)
5 => string '2016-05-22' (length=10)
6 => string '2016-05-23' (length=10)
I hope this answers your question... ;-)
Related
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;
}
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')
)
);
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;
});
}
What is the most efficient way to get a subarray of an array between two keys.
So for example,
$arr=array();
$arr['2014-03-01']='something';
$arr['2014-03-03']='something';
$arr['2014-02-04']='something';
$arr['2014-03-05']='something';
$arr['2014-03-07']='something';
$arr['2014-03-09']='something';
$arr['2014-01-04']='something';
$arr['2014-03-31']='something';
Get the subarray between two keys
i.e. start key:2014-02-04 and end key:2014-03-07 should return an array with only:
$arr['2014-02-04']='something';
$arr['2014-03-05']='something';
$arr['2014-03-07']='something';
Is there a quick and efficient way to do this without looping through the entire array?
UPDATE: I did a benchmark here is the results:
$arr=array();
for ($i=1;$i<=1000000;$i++) {
$arr["$i"]=$i;
}
$time_start=microtime_float();
$start = '20000';
$end = '20010';
$offset = array_search($start, array_keys($arr));
$length = array_search($end, array_keys($arr)) - $offset + 1;
$output = array_slice($arr, $offset, $length);
print_r($output);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "TIME=$time\n";
echo "\n============\n";
$time_start=microtime_float();
$result = array();
$start = '20000';
$end = '20010';
foreach ($arr as $key => $value) {
if ($key >= $start && $key <= $end)
$result[$key] = $value;
}
print_r($output);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "TIME=$time\n";
exit;
RESULTS:
Array
(
[0] => 20000
[1] => 20001
[2] => 20002
[3] => 20003
[4] => 20004
[5] => 20005
[6] => 20006
[7] => 20007
[8] => 20008
[9] => 20009
[10] => 20010
)
TIME=1.8481030464172
============
Array
(
[0] => 20000
[1] => 20001
[2] => 20002
[3] => 20003
[4] => 20004
[5] => 20005
[6] => 20006
[7] => 20007
[8] => 20008
[9] => 20009
[10] => 20010
)
TIME=1.700336933136
Hence, a simple loop seems to be slightly faster. The advantage increases if I make the start further down the array. You could also use break; once the latter point is reached.
The most efficient way is to use a loop.
$result = array();
$start = '2014-02-04';
$end = '2014-03-07';
foreach ($arr as $key => $value) {
// your date format is string comparable, otherwise use strtotime to convert to unix timestamp.
if ($key >= $start && $key <= $end) {
$result[$key] = $value;
}
}
Or less efficient way is using array_flip to exchange the key and value, then use array_filter to the required keys, then use array_intersect_key to get the result.
You can try with ksort, array_slice and array_search:
$start = '2014-02-04';
$end = '2014-03-07';
ksort($arr);
$offset = array_search($start, array_keys($arr));
$length = array_search($end, array_keys($arr)) - $offset + 1;
$output = array_slice($arr, $offset, $length);
var_dump($output);
Output:
array (size=5)
'2014-02-04' => string 'something' (length=9)
'2014-03-01' => string 'something' (length=9)
'2014-03-03' => string 'something' (length=9)
'2014-03-05' => string 'something' (length=9)
'2014-03-07' => string 'something' (length=9)
Given these two YYYYMM strings:
$start = "201301";
$end = "201303";
I would like to derive an array like this:
array (
0 =>
array (
0 => '20130101',
1 => '20130131',
),
1 =>
array (
0 => '20130201',
1 => '20130228',
),
2 =>
array (
0 => '20130301',
1 => '20130331',
),
)
I've tried a few things with date() and mktime() but nothing decent so far.
What's a nice way to do this?
With DateTime:
$start = "201301";
$end = "201303";
$dateNiceStart = substr($start,0,4).'-'.substr($start,4).'-01';
$dateNiceEnd = substr($end,0,4).'-'.substr($end,4).'-';
// Days count in month
$endDays = date('t',strtotime($dateNiceEnd.'01'));
$dateNiceEnd .= $endDays;
$startObj = new DateTime($dateNiceStart);
$endObj = new DateTime($dateNiceEnd);
$temp = clone $startObj;
$arr = array();
// Adding first month
//Using first day and last day
$temp->modify( 'first day of this month' );
$start = $temp->format('Ymd');
$temp->modify( 'last day of this month' );
$end = $temp->format('Ymd');
$arr[] = array($start, $end);
do{
// for next month
$temp->modify( 'first day of next month' );
$start = $temp->format('Ymd');
$temp->modify( 'last day of this month' );
$end = $temp->format('Ymd');
$arr[] = array($start, $end);
// This line edited to work properly in different years, thanks to #Adidi
$interval = $endObj->diff($temp)->format('%y%m%d');
}
while ($interval!=0);
print_R($arr);
Main key is first/last day of next/this month usage.
http://www.php.net/manual/en/function.date.php
Which you need is format string "t":
t Number of days in the given month 28 through 31
Here is easy way to loop it..
$start = "201301";
$end = "201303";
$start_time = strtotime(implode('-',str_split($start,4)));
$end_time = strtotime(implode('-',str_split($end,4)));
$array = array();
if($start_time <= $end_time){
while($start_time <= $end_time){
$month = date('F', $start_time);
$array[] = array(
date('Ymd', strtotime("first day of {$month}", $start_time)),
date('Ymd', strtotime("last day of {$month}", $start_time)));
$start_time = strtotime("next month", $start_time);
}
}
Something like this?
for($i=1;$i<=12;$i++) {
$first = '2013'.($i<10 ? '0'.$i : $i).'01';
$last = date('Ymt', strtotime($first));
$myArray[] = array($first, $last);
}
Not tested.
You can iterate over the months like so:
function date_range($start, $end)
{
$start = strtotime("$start01");
$end = strtotime("$end01");
$res = array();
while ($start < $end) {
$next = strtotime("+1 month -1 day", $start);
$res[] = array(
date('Ymd', $start),
date('Ymd', $next),
);
$start = $next;
}
return $res;
}
Working solution:
$start = "201301";
$end = "201309";
function getDateTimeByString($str_date){
preg_match('/^([\d]{4})([\d]{2})$/',$str_date,$matches);
$dt = null;
if($matches){
$dt = new DateTime();
$dt->setDate($matches[1],$matches[2],1);
}
return $dt;
}
$start_dt = getDateTimeByString($start);
$end_dt = getDateTimeByString($end);
$output = array();
while($start_dt->getTimestamp() <= $end_dt->getTimestamp()){
$arr = array();
$arr[] = $start_dt->format('Ymd');
$start_dt->modify('last day of this month');
$arr[] = $start_dt->format('Ymd');
$output[] = $arr;
$start_dt->modify('first day of next month');
}
print_r($output);
prints:
Array
(
[0] => Array
(
[0] => 20130101
[1] => 20130131
)
[1] => Array
(
[0] => 20130201
[1] => 20130228
)
[2] => Array
(
[0] => 20130301
[1] => 20130331
)
[3] => Array
(
[0] => 20130401
[1] => 20130430
)
[4] => Array
(
[0] => 20130501
[1] => 20130531
)
[5] => Array
(
[0] => 20130601
[1] => 20130630
)
[6] => Array
(
[0] => 20130701
[1] => 20130731
)
[7] => Array
(
[0] => 20130801
[1] => 20130831
)
[8] => Array
(
[0] => 20130901
[1] => 20130930
)
)
You can try with these functions :
function get_date_range ($start, $end) {
$dates = array();
$start = strtotime($start .'01');
$end = strtotime($end .'01');
while ($start <= $end) {
$dates [] = array(date('Ym01', $start), date('Ymt', $start));
$start = strtotime(add_month(date('Y-m-01', $start), 1));
}
return $dates;
}
function add_month($date_value, $months, $format = 'm/d/Y') {
$date = new DateTime($date_value);
$start_day = $date->format('j');
$date->modify("+{$months} month");
$end_day = $date->format('j');
if ($start_day != $end_day)
$date->modify('last day of last month');
return $date->format($format);
}
$start = "201301";
$end = "201303";
$dates = get_date_range($start, $end);
print_r($dates);
Here the add_month function will help you to avoid problems with the date when adding one month to January 31st.
If you use strtotime it will go to March when adding 1 month to January 31st..
Output will be :
Array
(
[0] => Array
(
[0] => 2013-01-01
[1] => 2013-01-31
)
[1] => Array
(
[0] => 2013-02-01
[1] => 2013-02-28
)
[2] => Array
(
[0] => 2013-03-01
[1] => 2013-03-31
)
)
Hope this helps you :)