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?
16 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.– salatheCommented Jul 8, 2010 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.– ChrisCommented May 30, 2013 at 9:00 -
43If you want to include the end date to your interval, you can do : $end = $end->modify( '+1 day' ); Commented Nov 14, 2014 at 13:52
-
3Is it possible to use this but reverse it, to loop back in history?– JonCommented Oct 22, 2017 at 18:39
-
4@JulienITARD thats a pretty good idea but more elegant would be $end->add( $interval ) because it responds directly to a changed interval ;)– GDYCommented Jun 6, 2019 at 8:36
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.
-
4Be sure to note that
$begin
will be different after the loop. This loop modifies the object created bynew DateTime( "2015-07-03" )
. Hence why you ought to use the DateTimeImmutable versions. But you need some further modifications for using them. Commented Sep 9, 2019 at 9: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.
-
4I don't like the look of that 86400. I understand that it is 60 * 60 * 24, but still... something about it irks me.– MikeDCommented Jul 8, 2010 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...– oeziCommented Jul 8, 2010 at 20:46
-
3Mike, the best thing to do is setup a constant and name it "DAY" so it becomes far easier to read. Commented Jul 8, 2010 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. Commented Feb 19, 2014 at 8: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.– sbrbotCommented Jun 4, 2015 at 22:35
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>";
}
-
2this 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– OrcraCommented Mar 14, 2020 at 2: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: php.net/manual/en/dateinterval.construct.php– joeljpaCommented Feb 15, 2023 at 7: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
)
$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);
-
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.– IfnotCommented Jun 24, 2013 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
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.
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!
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;
}
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);
}
$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.
<?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)));
}
?>
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.
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;
The more elastic example
//dilo surucu
class Day
{
private DateTimeInterface $dateTime;
public function __construct(DateTimeInterface $dateTime)
{
$this->dateTime = $dateTime;
}
public function today(string $format='Y-m-d'): string
{
return $this->dateTime->format($format);
}
public function yesterday(string $format='Y-m-d'): string
{
$today = $this->today();
return date($format, strtotime("$today -1 days"));
}
public function tomorrow(string $format='Y-m-d'): string
{
$today = $this->today();
return date($format, strtotime("$today +1 days"));
}
}
class DayIterator implements Iterator
{
private DateTimeInterface $currentDate;
private DateTimeInterface $endDate;
/**
* @throws Exception
*/
public function __construct(string $startDate, string $endDate)
{
$this->currentDate = new DateTime($startDate);
$this->endDate = new DateTime($endDate);
}
public function current(): Day
{
return new Day($this->currentDate);
}
public function key(): string
{
return $this->currentDate->format('Y-m-d');
}
public function next(): void
{
$this->currentDate = $this->currentDate->add(new DateInterval('P1D'));
}
public function rewind(): void
{
}
public function valid(): bool
{
return $this->currentDate <= $this->endDate;
}
}
// Usage
$dayIterator = new DayIterator(
'2024-01-01',
'2024-01-12'
);
foreach ($dayIterator as $day) {
echo 'Yesterday: ' . $day->yesterday('D Y-m-d') . PHP_EOL;
echo 'Date: ' . $day->today('D Y-m-d D') . PHP_EOL;
echo 'Tomorrow: ' . $day->tomorrow('D Y-m-d') . PHP_EOL;
echo PHP_EOL;
}