How to group dates together in an array, removing any overlapping dates - php

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

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')
)
);

is it possible to break array like this?

$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... ;-)

PHP check if variable is smaller than previous item in array

I need a way to check if there are events that overlap each other. So I made an array with the start and end hour of every event. It looks like this:
Array
(
[0] => Array
(
[start] => 0930
[end] => 1200
)
[1] => Array
(
[start] => 1000
[end] => 1230
)
[2] => Array
(
[start] => 1300
[end] => 1530
)
)
This is what I've tried to check if there are events that overlap:
if ( $orders->have_posts() ):
while ($orders->have_posts()) : $orders->the_post();
foreach($order as $o){
$start = $o['start'];
$end = $o['end'];
$attractieID = $o['attractie']->ID;
foreach($order as $key => $attractieID){
$slots[] = array('start' => $start, 'end' => $end);
if($start < $end){
//overlap
}else{
//no overlap
}
}
}
endwhile;
endif;
But this will always give true since I am checking the start and end date of the same item in my array.
I need to way to compare the start value of the current array item and the end value of the previous array item
Anyone knows if this is even possible?
Many thanks in advance!
Start looping at index 1, and compare the start time of the current event with the end of the event with index-1.
$count = count($order);
for ($i = 1; $i < $count; $i++) {
if ($order[$i]['start'] < $order[$i-1]['end']) {
// overlap
} else {
// no overlap
}
}
If you want to do this while also copying from $order to slots, you can use a variable to hold the end time from the previous iteration.
$prevEnd = null;
foreach($order as $o){
$start = $o['start'];
$end = $o['end'];
$attractieID = $o['attractie']->ID;
$slots[] = array('start' => $start, 'end' => $end);
if($prevEnd !== null && $start < $prevEnd){
//overlap
}else{
//no overlap
}
$prevEnd = $end;
}
DEMO
Try this code, with a for loop instead of foreach:
for($i=0;$i<count($order);i++){
$slots[] = array('start' => $start, 'end' => $end);
if($order[$i+1]){
if($order[$i]['start'] < $order[$i+1]['end']{
//overklap
}else{
//no overlap
}
}
Just use a normal for loop. And, to be sure everything is right, sort the array before checking it (if you are sure it is gona be sorted, you can skip that part)
$sortedOrders = usort($order, function($a, $b)
{
$aStart = $a['start'];
$bStart = $b['start'];
return ($a < $b) ? -1 : 1;
});
$count = count($sortedOrders);
for($i = 1; $i < $count; $i++)
{
if($sortedOrders[$i - 1]['end'] > $sortedOrders[$i]['start'])
{
// Handle overlap
}
}

How to get calendar weeks between two days correctly

Hi i need a code to get the week calendar numbers between two dates. I testes a little with some code from here but always get the wrong calendar numbers.
First Code :
$startDateUnix = strtotime('2014-09-21');
$endDateUnix = strtotime('2014-10-06');
$currentDateUnix = $startDateUnix;
$weekNumbers = array();
while ($currentDateUnix < $endDateUnix) {
$weekNumbers[] = date('W', $currentDateUnix);
$currentDateUnix = strtotime('+1 week', $currentDateUnix);
}
print_r($weekNumbers);
Second Code:
$start = '2014-09-22';
$end = '2014-10-06';
$dates = range(strtotime($start), strtotime($end),604800);
$weeks = array_map(function($v){return date('W', $v);}, $dates); // Requires PHP 5.3+
print_r($weeks);
and i get this out of both codes:
Array ( [0] => 38 [1] => 39 [2] => 40 )
But why is calendar week 41 not in ?
your second code returns the result like you expect:
$start = '2014-09-22';
$end = '2014-10-06';
$dates = range(strtotime($start), strtotime($end),604800);
$weeks = array_map(function($v){return date('W', $v);}, $dates); // Requires PHP 5.3+
print_r($weeks);
output:
Array
(
[0] => 39
[1] => 40
[2] => 41
)
the problem with your first code is that you start with 2014-09-21 (KW 38) and adding one week per loop. therefore the loop ends before the end date.
you can solve this by using the first code like this:
$startDateUnix = strtotime('2014-09-21');
$endDateUnix = strtotime('2014-10-06');
$currentDateUnix = $startDateUnix;
$weekNumbers = array();
while ($currentDateUnix <= $endDateUnix) {
$weekNumbers[] = date('W', $currentDateUnix);
$currentDateUnix = strtotime('+1 day', $currentDateUnix);
}
$weekNumbers = array_merge(array_unique($weekNumbers)); // array_merge to "reset" the keys
print_r($weekNumbers);
output:
Array
(
[0] => 38
[1] => 39
[2] => 40
[3] => 41
)

PHP: Return all dates between two dates in an array [duplicate]

This question already has answers here:
I have 2 dates in PHP, how can I run a foreach loop to go through all of those days?
(13 answers)
Closed 4 years ago.
Expected Input:
getDatesFromRange( '2010-10-01', '2010-10-05' );
Expected Output:
Array( '2010-10-01', '2010-10-02', '2010-10-03', '2010-10-04', '2010-10-05' )
You could also take a look at the DatePeriod class:
$period = new DatePeriod(
new DateTime('2010-10-01'),
new DateInterval('P1D'),
new DateTime('2010-10-05')
);
Which should get you an array with DateTime objects.
To iterate
foreach ($period as $key => $value) {
//$value->format('Y-m-d')
}
function createDateRangeArray($strDateFrom,$strDateTo)
{
// takes two dates formatted as YYYY-MM-DD and creates an
// inclusive array of the dates between the from and to dates.
// could test validity of dates here but I'm already doing
// that in the main script
$aryRange = [];
$iDateFrom = mktime(1, 0, 0, substr($strDateFrom, 5, 2), substr($strDateFrom, 8, 2), substr($strDateFrom, 0, 4));
$iDateTo = mktime(1, 0, 0, substr($strDateTo, 5, 2), substr($strDateTo, 8, 2), substr($strDateTo, 0, 4));
if ($iDateTo >= $iDateFrom) {
array_push($aryRange, date('Y-m-d', $iDateFrom)); // first entry
while ($iDateFrom<$iDateTo) {
$iDateFrom += 86400; // add 24 hours
array_push($aryRange, date('Y-m-d', $iDateFrom));
}
}
return $aryRange;
}
source: http://boonedocks.net/mike/archives/137-Creating-a-Date-Range-Array-with-PHP.html
This is very very flexible.
/**
* Creating date collection between two dates
*
* <code>
* <?php
* # Example 1
* date_range("2014-01-01", "2014-01-20", "+1 day", "m/d/Y");
*
* # Example 2. you can use even time
* date_range("01:00:00", "23:00:00", "+1 hour", "H:i:s");
* </code>
*
* #author Ali OYGUR <alioygur#gmail.com>
* #param string since any date, time or datetime format
* #param string until any date, time or datetime format
* #param string step
* #param string date of output format
* #return array
*/
function date_range($first, $last, $step = '+1 day', $output_format = 'd/m/Y' ) {
$dates = array();
$current = strtotime($first);
$last = strtotime($last);
while( $current <= $last ) {
$dates[] = date($output_format, $current);
$current = strtotime($step, $current);
}
return $dates;
}
Note that the answer provided by ViNce does NOT include the end date for the period.
If you are using PHP 5.3+, your best bet is to use a function like this:
/**
* Generate an array of string dates between 2 dates
*
* #param string $start Start date
* #param string $end End date
* #param string $format Output format (Default: Y-m-d)
*
* #return array
*/
function getDatesFromRange($start, $end, $format = 'Y-m-d') {
$array = array();
$interval = new DateInterval('P1D');
$realEnd = new DateTime($end);
$realEnd->add($interval);
$period = new DatePeriod(new DateTime($start), $interval, $realEnd);
foreach($period as $date) {
$array[] = $date->format($format);
}
return $array;
}
Then, you would call the function as expected:
getDatesFromRange('2010-10-01', '2010-10-05');
Run demo
Note about DatePeriod class: You can use the 4th parameter of DatePeriod to exclude the start date (DatePeriod::EXCLUDE_START_DATE) but you cannot, at this time, include the end date.
Simple but like a charm:
$period = new DatePeriod(new DateTime('2015-01-01'), new DateInterval('P1D'), new DateTime('2015-01-15 +1 day'));
foreach ($period as $date) {
$dates[] = $date->format("Y-m-d");
}
//ONLY SHOWING
echo '<pre>';
var_dump($dates);
echo '</pre>';
exit();
function GetDays($sStartDate, $sEndDate){
// Firstly, format the provided dates.
// This function works best with YYYY-MM-DD
// but other date formats will work thanks
// to strtotime().
$sStartDate = gmdate("Y-m-d", strtotime($sStartDate));
$sEndDate = gmdate("Y-m-d", strtotime($sEndDate));
// Start the variable off with the start date
$aDays[] = $sStartDate;
// Set a 'temp' variable, sCurrentDate, with
// the start date - before beginning the loop
$sCurrentDate = $sStartDate;
// While the current date is less than the end date
while($sCurrentDate < $sEndDate){
// Add a day to the current date
$sCurrentDate = gmdate("Y-m-d", strtotime("+1 day", strtotime($sCurrentDate)));
// Add this new day to the aDays array
$aDays[] = $sCurrentDate;
}
// Once the loop has finished, return the
// array of days.
return $aDays;
}
use like
GetDays('2007-01-01', '2007-01-31');
You must add $end->modify('+1 day') to include last day of interval, for example the January will have a 31 days instead of 30 without using modify() method.
This version of code will include the last day of the interval:
$begin = new DateTime( '2018-08-01' );
$end = new DateTime( '2018-08-31' );
$end = $end->modify( '+1 day' );
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);
foreach($daterange as $date){
echo $date->format("Ymd") . "<br>";
}
PHP doc link
This is short, sweet, and should work in PHP4+.
function getDatesFromRange($start, $end){
$dates = array($start);
while(end($dates) < $end){
$dates[] = date('Y-m-d', strtotime(end($dates).' +1 day'));
}
return $dates;
}
Short function. PHP 5.3 and up. Can take optional third param of any date format that strtotime can understand. Automatically reverses direction if end < start.
function getDatesFromRange($start, $end, $format='Y-m-d') {
return array_map(function($timestamp) use($format) {
return date($format, $timestamp);
},
range(strtotime($start) + ($start < $end ? 4000 : 8000), strtotime($end) + ($start < $end ? 8000 : 4000), 86400));
}
Test:
date_default_timezone_set('Europe/Berlin');
print_r(getDatesFromRange( '2016-7-28','2016-8-2' ));
print_r(getDatesFromRange( '2016-8-2','2016-7-28' ));
print_r(getDatesFromRange( '2016-10-28','2016-11-2' ));
print_r(getDatesFromRange( '2016-11-2','2016-10-28' ));
print_r(getDatesFromRange( '2016-4-2','2016-3-25' ));
print_r(getDatesFromRange( '2016-3-25','2016-4-2' ));
print_r(getDatesFromRange( '2016-8-2','2016-7-25' ));
print_r(getDatesFromRange( '2016-7-25','2016-8-2' ));
Output:
Array ( [0] => 2016-07-28 [1] => 2016-07-29 [2] => 2016-07-30 [3] => 2016-07-31 [4] => 2016-08-01 [5] => 2016-08-02 )
Array ( [0] => 2016-08-02 [1] => 2016-08-01 [2] => 2016-07-31 [3] => 2016-07-30 [4] => 2016-07-29 [5] => 2016-07-28 )
Array ( [0] => 2016-10-28 [1] => 2016-10-29 [2] => 2016-10-30 [3] => 2016-10-31 [4] => 2016-11-01 [5] => 2016-11-02 )
Array ( [0] => 2016-11-02 [1] => 2016-11-01 [2] => 2016-10-31 [3] => 2016-10-30 [4] => 2016-10-29 [5] => 2016-10-28 )
Array ( [0] => 2016-04-02 [1] => 2016-04-01 [2] => 2016-03-31 [3] => 2016-03-30 [4] => 2016-03-29 [5] => 2016-03-28 [6] => 2016-03-27 [7] => 2016-03-26 [8] => 2016-03-25 )
Array ( [0] => 2016-03-25 [1] => 2016-03-26 [2] => 2016-03-27 [3] => 2016-03-28 [4] => 2016-03-29 [5] => 2016-03-30 [6] => 2016-03-31 [7] => 2016-04-01 [8] => 2016-04-02 )
Array ( [0] => 2016-08-02 [1] => 2016-08-01 [2] => 2016-07-31 [3] => 2016-07-30 [4] => 2016-07-29 [5] => 2016-07-28 [6] => 2016-07-27 [7] => 2016-07-26 [8] => 2016-07-25 )
Array ( [0] => 2016-07-25 [1] => 2016-07-26 [2] => 2016-07-27 [3] => 2016-07-28 [4] => 2016-07-29 [5] => 2016-07-30 [6] => 2016-07-31 [7] => 2016-08-01 [8] => 2016-08-02 )
Here is a function, that will return date ranges in both directions and it works on PHP >=5.2.2 :
function createRange($start, $end, $format = 'Y-m-d') {
$start = new DateTime($start);
$end = new DateTime($end);
$invert = $start > $end;
$dates = array();
$dates[] = $start->format($format);
while ($start != $end) {
$start->modify(($invert ? '-' : '+') . '1 day');
$dates[] = $start->format($format);
}
return $dates;
}
Use example:
print_r(createRange('2010-10-01', '2010-10-05'));
/*Array
(
[0] => 2010-10-01
[1] => 2010-10-02
[2] => 2010-10-03
[3] => 2010-10-04
[4] => 2010-10-05
)*/
print_r(createRange('2010-10-05', '2010-10-01', 'j M Y'));
/*Array
(
[0] => 5 Oct 2010
[1] => 4 Oct 2010
[2] => 3 Oct 2010
[3] => 2 Oct 2010
[4] => 1 Oct 2010
)*/
demo
many ways of getting this done, but finally it all depends on PHP version you are using. Here is summary of all solutions:
get PHP version:
echo phpinfo();
PHP 5.3+
$period = new DatePeriod(
new DateTime('2010-10-01'),
new DateInterval('P1D'),
new DateTime('2010-10-05')
);
PHP 4+
/**
* creating between two date
* #param string since
* #param string until
* #param string step
* #param string date format
* #return array
* #author Ali OYGUR <alioygur#gmail.com>
*/
function dateRange($first, $last, $step = '+1 day', $format = 'd/m/Y' ) {
$dates = array();
$current = strtotime($first);
$last = strtotime($last);
while( $current <= $last ) {
$dates[] = date($format, $current);
$current = strtotime($step, $current);
}
return $dates;
}
PHP < 4
you should upgrade :)
// Specify the start date. This date can be any English textual format
$date_from = "2018-02-03";
$date_from = strtotime($date_from); // Convert date to a UNIX timestamp
// Specify the end date. This date can be any English textual format
$date_to = "2018-09-10";
$date_to = strtotime($date_to); // Convert date to a UNIX timestamp
// Loop from the start date to end date and output all dates inbetween
for ($i=$date_from; $i<=$date_to; $i+=86400) {
echo date("Y-m-d", $i).'<br />';
}
<?
print_r(getDatesFromRange( '2010-10-01', '2010-10-05' ));
function getDatesFromRange($startDate, $endDate)
{
$return = array($startDate);
$start = $startDate;
$i=1;
if (strtotime($startDate) < strtotime($endDate))
{
while (strtotime($start) < strtotime($endDate))
{
$start = date('Y-m-d', strtotime($startDate.'+'.$i.' days'));
$return[] = $start;
$i++;
}
}
return $return;
}
Solution for PHP 5.2 with DateTime objects. But startDate MUST be before endDate.
function createRange($startDate, $endDate) {
$tmpDate = new DateTime($startDate);
$tmpEndDate = new DateTime($endDate);
$outArray = array();
do {
$outArray[] = $tmpDate->format('Y-m-d');
} while ($tmpDate->modify('+1 day') <= $tmpEndDate);
return $outArray;
}
Using:
$dates = createRange('2010-10-01', '2010-10-05');
$dates contain:
Array( '2010-10-01', '2010-10-02', '2010-10-03', '2010-10-04', '2010-10-05' )
function createDateRangeArray($start, $end) {
// Modified by JJ Geewax
$range = array();
if (is_string($start) === true) $start = strtotime($start);
if (is_string($end) === true ) $end = strtotime($end);
if ($start > $end) return createDateRangeArray($end, $start);
do {
$range[] = date('Y-m-d', $start);
$start = strtotime("+ 1 day", $start);
}
while($start < $end);
return $range;
}
Source: http://boonedocks.net/mike/archives/137-Creating-a-Date-Range-Array-with-PHP.html
$report_starting_date=date('2014-09-16');
$report_ending_date=date('2014-09-26');
$report_starting_date1=date('Y-m-d',strtotime($report_starting_date.'-1 day'));
while (strtotime($report_starting_date1)<strtotime($report_ending_date))
{
$report_starting_date1=date('Y-m-d',strtotime($report_starting_date1.'+1 day'));
$dates[]=$report_starting_date1;
}
print_r($dates);
// dates ('2014-09-16', '2014-09-26')
//print result Array
(
[0] => 2014-09-16
[1] => 2014-09-17
[2] => 2014-09-18
[3] => 2014-09-19
[4] => 2014-09-20
[5] => 2014-09-21
[6] => 2014-09-22
[7] => 2014-09-23
[8] => 2014-09-24
[9] => 2014-09-25
[10] => 2014-09-26
)
Here's a way of doing this using Carbon https://github.com/briannesbitt/Carbon:
public function buildDateRangeArray($first, $last)
{
while ($first <= $last) {
$dates[] = $first->toDateString();
$first->addDay();
}
return $dates;
}
This, of course, can be tweaked to not use Carbon. The $first and $last parameters passed to the function are Carbon instances.
// will return dates array
function returnBetweenDates( $startDate, $endDate ){
$startStamp = strtotime( $startDate );
$endStamp = strtotime( $endDate );
if( $endStamp > $startStamp ){
while( $endStamp >= $startStamp ){
$dateArr[] = date( 'Y-m-d', $startStamp );
$startStamp = strtotime( ' +1 day ', $startStamp );
}
return $dateArr;
}else{
return $startDate;
}
}
returnBetweenDates( '2014-09-16', '2014-09-26' );
// print_r( returnBetweenDates( '2014-09-16', '2014-09-26' ) );
it will return array like below:
Array
(
[0] => 2014-09-16
[1] => 2014-09-17
[2] => 2014-09-18
[3] => 2014-09-19
[4] => 2014-09-20
[5] => 2014-09-21
[6] => 2014-09-22
[7] => 2014-09-23
[8] => 2014-09-24
[9] => 2014-09-25
[10] => 2014-09-26
)
I think it's the shortest answer
Edit the code as you like
for ($x=strtotime('2015-12-01');$x<=strtotime('2015-12-30');$x+=86400)
echo date('Y-m-d',$x);
I love a solid one-liner!
My php discovery of the day was that array_push() returns the new number of elements in the array.
I managed to check for the end date match, increment $x, and push new elements all within the two-part condition statement of an empty while loop.
function getDatesFromRange($a,$b,$x=0,$dates=[]){
while(end($dates)!=$b && $x=array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
return $dates;
}
var_export(getDatesFromRange('2010-10-01','2010-10-05'));
The most similar function to mine on this page is drolex's (which I didn't actually find until after I wrote mine, if you believe me). I did some speed tests across large and small date ranges and they seem to beat each other just as often -- so I'm calling them equal performers. Here are some other comparisons:
We both use date(), strtotime(), and two array functions.
Drolex uses just three variables, I use the same three plus $x.
Because loading the start date into the $date array is not necessary for my function, I can declare it in the function parameters and spare the line (likewise with $x).
**Just a couple of important notes:
1- Date strings MUST BE validated before being fed to the function.
2- The above function can only handle forward moving date ranges.
If you want backward moving date ranges, simply reverse the date order in the function call and add a minus after $x=. (Pretty slick, eh?)
function getDatesFromRange($a,$b,$x=0,$dates=[]){
while(end($dates)!=$b && $x=-array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
return $dates;
}
var_export(getDatesFromRange('2010-10-05','2010-10-01'));
One more extension/consideration...
Imagine you have a multi-cultural (or sloppy) user base, and your function MUST be able to receive start and end dates in different valid formats AND you need to be able to output the array in any of the valid formats? By minor adjustment, I've provided a solution for that.
By "valid" I mean YYYY-MM-DD, MM/DD/YYY, and DD-MM-YYYY, these are massively popular standards world-wide, if another format is necessary then usability would come down to strtotime's comprehension of it.
Here is the Demo.
Code:
function getDatesFromRange($a,$b,$format='Y-m-d',$dates=[],$x=0){
while(date($format,strtotime(end($dates)))!=date($format,strtotime($b)) && $x=array_push($dates,date($format,strtotime("$a +$x day"))));
return $dates;
}
$formats=array("Computer"=>'Y-m-d',"American"=>'m/d/Y','Non-American'=>'d-m-Y');
$start='15-02-2017'; // Non-American formatted start date
$end='2017-02-27'; // Computer formatted start date
foreach($formats as $label=>$format){
echo "<br>$label<br>";
var_export(getDatesFromRange($start,$end,$format));
echo "<br>";
}
Output
Computer
array ( 0 => '2017-02-15', 1 => '2017-02-16', 2 => '2017-02-17', 3 => '2017-02-18',
4 => '2017-02-19', 5 => '2017-02-20', 6 => '2017-02-21', 7 => '2017-02-22',
8 => '2017-02-23', 9 => '2017-02-24', 10 => '2017-02-25', 11 => '2017-02-26',
12 => '2017-02-27', )
American
array ( 0 => '02/15/2017', 1 => '02/16/2017', 2 => '02/17/2017', 3 => '02/18/2017',
4 => '02/19/2017', 5 => '02/20/2017', 6 => '02/21/2017', 7 => '02/22/2017',
8 => '02/23/2017', 9 => '02/24/2017', 10 => '02/25/2017', 11 => '02/26/2017',
12 => '02/27/2017', )
Non-American
array ( 0 => '15-02-2017', 1 => '16-02-2017', 2 => '17-02-2017', 3 => '18-02-2017',
4 => '19-02-2017', 5 => '20-02-2017', 6 => '21-02-2017', 7 => '22-02-2017',
8 => '23-02-2017', 9 => '24-02-2017', 10 => '25-02-2017', 11 => '26-02-2017',
12 => '27-02-2017', )
Now some people don't 100% trust strtotime() because of some buggy behaviors. I think I've read that it will foul up when trying to jump a month from a leap-day. However, unless someone can reproduce it to prove me wrong, strtotime() is never going to let you down when you are only incrementing by one day.
Here is the another solution. Please check this.
$first = '10/30/2017'; //starting date
$last= '10/11/2017'; //ending date
$first_time_arr=explode('/',$first);
$last_time_arr=explode('/',$last);
//create timestamp of starting date
$start_timestamp=mktime(0,0,0, $first_time_arr[0], $first_time_arr[1],$first_time_arr[2]);
//create timestamp of ending date
$end_timestamp=mktime(0,0,0, $last_time_arr[0], $last_time_arr[1],$last_time_arr[2]);
$date_arr=array();
for($i=$start_timestamp;$i<=$end_timestamp;$i=$i+86400){
$date_arr[]=date("Y-m-d",$i); //this will save all dates in array
}
public static function countDays($date1,$date2)
{
$date1 = strtotime($date1); // or your date as well
$date2 = strtotime($date2);
$datediff = $date1 - $date2;
return floor($datediff/(60*60*24));
}
public static function dateRange($date1,$date2)
{
$count = static::countDays($date1,$date2) + 1;
$dates = array();
for($i=0;$i<$count;$i++)
{
$dates[] = date("Y-m-d",strtotime($date2.'+'.$i.' days'));
}
return $dates;
}
function datesbetween ($date1,$date2)
{
$dates= array();
for ($i = $date1
; $i<= $date1
; $i=date_add($i, date_interval_create_from_date_string('1 days')) )
{
$dates[] = clone $i;
}
return $dates;
}
To make Mostafa's answer complete, this is definietly the simplest and most efficient way to do it:
function getDatesFromRange($start_date, $end_date, $date_format = 'Y-m-d')
{
$dates_array = array();
for ($x = strtotime($start_date); $x <= strtotime($end_date); $x += 86400) {
array_push($dates_array, date($date_format, $x));
}
return $dates_array;
}
// see the dates in the array
print_r( getDatesFromRange('2017-02-09', '2017-02-19') );
You can even change the default output date format if you add a third parameter when you call the function, otherwise it will use the default format that's been set as 'Y-m-d'.
I hope it helps :)
function getWeekdayDatesFrom($format, $start_date_epoch, $end_date_epoch, $range) {
$dates_arr = array();
if( ! $range) {
$range = round(abs($start_date_epoch-$end_date_epoch)/86400) + 1;
} else {
$range = $range + 1; //end date inclusive
}
$current_date_epoch = $start_date_epoch;
for($i = 1; $i <= $range; $i+1) {
$d = date('N', $current_date_epoch);
if($d <= 5) { // not sat or sun
$dates_arr[] = "'".date($format, $current_date_epoch)."'";
}
$next_day_epoch = strtotime('+'.$i.'day', $start_date_epoch);
$i++;
$current_date_epoch = $next_day_epoch;
}
return $dates_arr;
}
$arr = range(strtotime("2013-12-01"),strtotime("2013-12-31"), "86400");
array_walk_recursive($arr, function(&$element) { $element = date("Y-m-d", $element); });
print_r ($arr);

Categories