I'm starting with a date 2010-05-01
and ending with 2010-05-10
. How can I iterate through all of those dates in PHP?

- 146,994
- 96
- 417
- 335

- 41,293
- 91
- 306
- 570
15 Answers
$begin = new DateTime('2010-05-01');
$end = new DateTime('2010-05-10');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $dt) {
echo $dt->format("l Y-m-d H:i:s\n");
}
This will output all days in the defined period between $start
and $end
. If you want to include the 10th, set $end
to 11th. You can adjust format to your liking. See the PHP Manual for DatePeriod. It requires PHP 5.3.
-
2good news - there is a patch for setting a flag to include the end date which (fingers crossed) will make it into a future version. – salathe Jul 08 '10 at 20:51
-
11`$begin->setTime(0,0); $end->setTime(12,0);` or initializing with the time of day of the start date as any time later than that of the end date will include the end date in the loop. Not the most stylish fix, but it's the best option as long as there's not a proper flag. – Chris May 30 '13 at 09:00
-
2This also doesn't work if the start and end dates are the same (say you are letting someone pick the start and end dates in a date picker), so I add one day to the end date – Matthew Lock Oct 24 '13 at 09:14
-
1@MatthewLock umm, out of curiosity, what you did you expect it to do when the start and end date are on the same day? I mean, there is no days to go through then, so it's kinda obvious that it doesn't work then. – Gordon Oct 24 '13 at 10:06
-
1I expected it to include the last day (which is the same as the first) so to each one date (the first/last date) – Matthew Lock Oct 24 '13 at 13:21
-
1it looks to be a clean way, but it is not the most efficient: creating the array causes a loop and and also extra mem utilization. for+computation loops as proposed in other answers are harder to read but more efficient in execution. – Quicker Sep 02 '14 at 07:04
-
43If you want to include the end date to your interval, you can do : $end = $end->modify( '+1 day' ); – JulienITARD Nov 14 '14 at 13:52
-
3Is it possible to use this but reverse it, to loop back in history? – Jon Oct 22 '17 at 18:39
-
@Gordon I realized after I posted that it was a dumb question. You can’t actually just reverse the dates, as that seems to make it fail though. But for my use, I ended up just using the start date in the past and it worked. – Jon Oct 22 '17 at 21:08
-
4@JulienITARD thats a pretty good idea but more elegant would be $end->add( $interval ) because it responds directly to a changed interval ;) – GDY Jun 06 '19 at 08:36
-
This is wrong! You aint get all the dates – YanAlex Dec 02 '21 at 14:27
-
@user1713785 how so? https://3v4l.org/u63FH does exactly what my answer describes. – Gordon Dec 03 '21 at 11:36
-
@Gordon you lost 2010-05-10 – YanAlex Dec 07 '21 at 07:01
-
@user see my answer "If you want to include the 10th, set $end to 11th." Or use what JulienITARD suggested in the comments above. In any case: works as described. – Gordon Dec 07 '21 at 15:22
-
I created a [LiveDemo](https://ideone.com/H0EfzZ) for this beautiful answer with `leap year` example and the trick of issuing the `setTime()` to include end date into results set. Gordon thanks for your post and @Chris for the time trick! – ino Mar 15 '22 at 09:11
This also includes the last date
$begin = new DateTime( "2015-07-03" );
$end = new DateTime( "2015-07-09" );
for($i = $begin; $i <= $end; $i->modify('+1 day')){
echo $i->format("Y-m-d");
}
If you dont need the last date just remove =
from the condition.

- 4,084
- 5
- 30
- 45
-
3Be sure to note that `$begin` will be *different* after the loop. This loop modifies the object created by `new DateTime( "2015-07-03" )`. Hence why you ought to use the DateTimeImmutable versions. But you need some further modifications for using them. – Henk Poley Sep 09 '19 at 09:44
Converting to unix timestamps makes doing date math easier in php:
$startTime = strtotime( '2010-05-01 12:00' );
$endTime = strtotime( '2010-05-10 12:00' );
// Loop between timestamps, 24 hours at a time
for ( $i = $startTime; $i <= $endTime; $i = $i + 86400 ) {
$thisDate = date( 'Y-m-d', $i ); // 2010-05-01, 2010-05-02, etc
}
When using PHP with a timezone having DST, make sure to add a time that is not 23:00, 00:00 or 1:00 to protect against days skipping or repeating.

- 401
- 5
- 15

- 3,329
- 2
- 23
- 22
-
4I don't like the look of that 86400. I understand that it is 60 * 60 * 24, but still... something about it irks me. – MikeD Jul 08 '10 at 20:37
-
14in this case, it works, but if there is a switch between normal and sunlight saving time, it will fail because there's a 90000 second-day that you'll have twice in your loop... – oezi Jul 08 '10 at 20:46
-
3Mike, the best thing to do is setup a constant and name it "DAY" so it becomes far easier to read. – The Pixel Developer Jul 08 '10 at 20:50
-
5This will suffer from daylight savings issues. When you cross a daylight savings time point, it will get screwed up. 12:00am isn't 12:00am on both sides of the point in time. – Eric Cope Feb 19 '14 at 08:13
-
1This code does (each code with 86400 seconds per day) have problem with daylight saving! With daylight saving some days last only 23 hours, and some 25 hours. – sbrbot Jun 04 '15 at 22:35
-
1Contrarily to what has been said in the latest comments, since it was edited by @Gordon (Mar 16 '13 at 9:18) this doesn't suffer from daylight issues anymore. The time is set to 12pm, so even with DST it could only become 11am or 1pm - which still remans in the same day. In the loop, he's only checking for the date without the time, there will be no days skipping or repeating. – Abu Junayd Dec 02 '15 at 14:57
-
-
This answer belongs to "Falsehoods programmers believe about time".. Certainly whenever there's a leapsecond it's "slightly" wrong, but still wrong. – Henk Poley Sep 10 '19 at 06:12
Copy from php.net sample for inclusive range:
$begin = new DateTime( '2012-08-01' );
$end = new DateTime( '2012-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>";
}

- 3,932
- 4
- 35
- 60

- 291
- 3
- 2
-
1this is the best and most complete answer. Only missing some explanation of the DateInterval value P1D, so here are some Period Designator examples Two days : P2D Two seconds : PT2S One week and ten minutes : P1WT10M Y for years M for months D for days W for weeks. These get converted into days, so can not be combined with D. H for hours M for minutes S for seconds – Orcra Mar 14 '20 at 02:45
-
@Orcra To further supplement your explanation: We use 'P1D' because the `DateInterval` constructor's `$duration` argument takes the letter P (for period), followed by the duration period represented by an integer value (in our case '1') and then by a period designator (in our case 'D'). Thus, a period duration of 1 day. Refer doc link for further information on using this: https://www.php.net/manual/en/dateinterval.construct.php – joeljpa Feb 15 '23 at 07:33
Here is another simple implementation -
/**
* Date range
*
* @param $first
* @param $last
* @param string $step
* @param string $format
* @return array
*/
function dateRange( $first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
$dates = [];
$current = strtotime( $first );
$last = strtotime( $last );
while( $current <= $last ) {
$dates[] = date( $format, $current );
$current = strtotime( $step, $current );
}
return $dates;
}
Example:
print_r( dateRange( '2010-07-26', '2010-08-05') );
Array (
[0] => 2010-07-26
[1] => 2010-07-27
[2] => 2010-07-28
[3] => 2010-07-29
[4] => 2010-07-30
[5] => 2010-07-31
[6] => 2010-08-01
[7] => 2010-08-02
[8] => 2010-08-03
[9] => 2010-08-04
[10] => 2010-08-05
)

- 2,829
- 1
- 26
- 26
$startTime = strtotime('2010-05-01');
$endTime = strtotime('2010-05-10');
// Loop between timestamps, 1 day at a time
$i = 1;
do {
$newTime = strtotime('+'.$i++.' days',$startTime);
echo $newTime;
} while ($newTime < $endTime);
or
$startTime = strtotime('2010-05-01');
$endTime = strtotime('2010-05-10');
// Loop between timestamps, 1 day at a time
do {
$startTime = strtotime('+1 day',$startTime);
echo $startTime;
} while ($startTime < $endTime);

- 6,316
- 2
- 29
- 47

- 209,507
- 32
- 346
- 385
-
2It appear that this solution is slower than accepted answer (un ran some benchs : 100% slower for 60 iterations). But i choose this one for retro compatibility for old hosting plateforms. – Ifnot Jun 24 '13 at 12:55
User this function:-
function dateRange($first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
$dates = array();
$current = strtotime($first);
$last = strtotime($last);
while( $current <= $last ) {
$dates[] = date($format, $current);
$current = strtotime($step, $current);
}
return $dates;
}
Usage / function call:-
Increase by one day:-
dateRange($start, $end); //increment is set to 1 day.
Increase by Month:-
dateRange($start, $end, "+1 month");//increase by one month
use third parameter if you like to set date format:-
dateRange($start, $end, "+1 month", "Y-m-d H:i:s");//increase by one month and format is mysql datetime

- 992
- 9
- 10
For Carbon
users
use Carbon\Carbon;
$startDay = Carbon::parse("2021-08-01");
$endDay= Carbon::parse("2021-08-05");
$period = $startDay->range($endDay, 1, 'day');
When I print the data
[
Carbon\Carbon @1627790400 {#4970
date: 2021-08-01 00:00:00.0 America/Toronto (-04:00),
},
Carbon\Carbon @1627876800 {#4974
date: 2021-08-02 00:00:00.0 America/Toronto (-04:00),
},
Carbon\Carbon @1627963200 {#4978
date: 2021-08-03 00:00:00.0 America/Toronto (-04:00),
},
Carbon\Carbon @1628049600 {#5007
date: 2021-08-04 00:00:00.0 America/Toronto (-04:00),
},
Carbon\Carbon @1628136000 {#5009
date: 2021-08-05 00:00:00.0 America/Toronto (-04:00),
},
]
This is Laravel data dump using dd($period->toArray());
. You can now iterate through $period
if you want with a foreach
statement.
One important note - it includes both the edge dates provided to method.
For more cool date related stuff, do check out the Carbon docs.

- 42,008
- 16
- 111
- 154

- 650
- 10
- 12
here's a way:
$date = new Carbon();
$dtStart = $date->startOfMonth();
$dtEnd = $dtStart->copy()->endOfMonth();
$weekendsInMoth = [];
while ($dtStart->diffInDays($dtEnd)) {
if($dtStart->isWeekend()) {
$weekendsInMoth[] = $dtStart->copy();
}
$dtStart->addDay();
}
The result of $weekendsInMoth is array of weekend days!

- 21
- 1
If you're using php version less than 8.2 and don't have the DatePeriod::INCLUDE_END_DATE
const. I wrote a method that returns an array of \DateTimeImmutable
.
This works with a start date before, the same or after the end date.
/**
* @param DateTimeImmutable $start
* @param DateTimeImmutable $end
* @return array<\DateTimeImmutable>
*/
public static function getRangeDays(\DateTimeImmutable $start, \DateTimeImmutable $end): array
{
$startDate = $start;
$endDate = $end;
$forwards = $endDate >= $startDate;
$carryDate = $startDate;
$days = [];
while (true) {
if (($forwards && $carryDate > $end) || (!$forwards && $carryDate < $end)) {
break;
}
$days[] = $carryDate;
if ($forwards) {
$carryDate = $carryDate->modify('+1 day');
} else {
$carryDate = $carryDate->modify('- 1 day');
}
}
return $days;
}

- 261
- 2
- 6
$date = new DateTime($_POST['date']);
$endDate = date_add(new DateTime($_POST['date']),date_interval_create_from_date_string("7 days"));
while ($date <= $endDate) {
print date_format($date,'d-m-Y')." AND END DATE IS : ".date_format($endDate,'d-m-Y')."\n";
date_add($date,date_interval_create_from_date_string("1 days"));
}
You can iterate like this also, The $_POST['date']
can be dent from your app or website
Instead of $_POST['date']
you can also place your string here "21-12-2019"
. Both will work.

- 101
- 1
- 9
<?php
$start_date = '2015-01-01';
$end_date = '2015-06-30';
while (strtotime($start_date) <= strtotime($end_date)) {
echo "$start_daten";
$start_date = date ("Y-m-d", strtotime("+1 days", strtotime($start_date)));
}
?>

- 41
- 3
Just a thought with the while loop
$startDate = '2023-03-01';
$endDate = '2023-04-01';
$currentDate = strtotime($startDate);
$endDate = strtotime($endDate);
while ($currentDate <= $endDate) {
echo date('Y-m-d', $currentDate) . "\n";
$currentDate = strtotime('+1 day', $currentDate);
}

- 11
- 3
I like using simple, clean and library-less methods like this:
function datesBetween($startDate, $endDate)
{
$dates = [];
$start = new DateTime($startDate);
$end = new DateTime($endDate);
while ($start <= $end) {
$dates[] = $start->format('Y-m-d');
$start->modify('+1 day');
}
return $dates;
}
Hope it helps someone.

- 5,372
- 10
- 54
- 79
If you use Laravel and want to use Carbon the correct solution would be the following:
$start_date = Carbon::createFromFormat('Y-m-d', '2020-01-01');
$end_date = Carbon::createFromFormat('Y-m-d', '2020-01-31');
$period = new CarbonPeriod($start_date, '1 day', $end_date);
foreach ($period as $dt) {
echo $dt->format("l Y-m-d H:i:s\n");
}
Remember to add:
- use Carbon\Carbon;
- use Carbon\CarbonPeriod;

- 119
- 2
- 12