Generate range of dates in PHP

This code is from ancient PHP 5.2 days. For modern projects use something more recent, like Period library.

Date and time values are nightmare in the world of binary (or decimal at best). There are different time formats (almost freeform), time zones, daylight saving offsets and who knows what else to consider.

As with any tricky task my rule of a thumb is to trust programming language and don’t trust Googled-up snippets too much. I needed range of days for one graph in Google Charts so I tried to make compact, flexible (and me-proof) function to generate range of dates.

Things to remember

It is important to establish time zone environment. In modern versions of PHP (which you should be using) is is handled by date_default_timezone_set function (or date.timezone in configuration). Functions that are sensitive to that will even try to raise fuss if it isn’t set.

You can format output however you like, but it is important to be very careful with date inputs. PHP does its best to interpret them, but for X possible ways to write down date there are twice that ways it can go wrong.

PHP manual has proper list of date formats. Pick one and stick with it. Since here I am writing for primary audience with different (and crazy, who puts  month before day??) date format I stick to ISO formats in clear descending order.

And finally since programs usually deal with time as amount of seconds it seems easy to treat time spans as set of those (60*60*24). Bad idea to use bunch of seconds. That only works until you hit daylight saving shift or something as obscure. Will show how to work around that in my function.

Resulting 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;
}

Example usage

Daily defaults:

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

)

Full week interval:

print_r( dateRange( '2010/07/26', '2010/08/05', '+1 week') );

Array (

[0] => 2010/07/26

[1] => 2010/08/02

)

How it works

Function takes:

  • range as two dates (remember to pick bulletproof format);
  • interval to generate dates (defaults to one day);
  • format for date output (cosmetic).

Bulk of function is simple loop that creates dates by skipping in specified interval until out of range.

Trick part is how much to skip. strtotime function handles that. It takes timestamp value of current date and adds interval to it. It is smart enough to handle daylight saving time issues and is way more reliable than using bunch of seconds for interval.

Overall

Dates are tricky. Going over docs carefully and leaving as much as possible to native language functions is best approach to ensure nothing gets miscalculated.

Function could (and should) be extended a bit to handle corner cases better, but works fine for my current needs.

Related Posts

11 Comments

  • You won’t believe it, but this is EXACTLY what I needed. Very well done :-)

  • Glad it was of use. :) Extensive functions for dates and time in PHP are awesome to make snippets this short, but accurate.

  • very useful!! thank you very much :)

  • Thank you! Lots of bad examples out there, but this one was very short and clean. Great, this’ll become handy! Thanks :-)

  • you have know idea how awesome this is..there’s just so much convulated info on the web.. thanks..my app can proceed

  • thanks for your nice code. it is useful but how can i skip weedend?

  • @mahdi

    I don’t see the point of including weekend logic in this code. You can always loop through the range afterward and exclude days that fall on weekends.


  • $start = implode('-', array_reverse( explode("/",$start_date) ) );
    $stop = implode('-', array_reverse( explode("/",$end_date) ) );
    $arDates = array();
    $begin = new DateTime($start );
    $end = new DateTime( $stop );
    $end = $end->modify( '+1 day' );

    $interval = new DateInterval('P1D');
    $daterange = new DatePeriod($begin, $interval ,$end);

    foreach($daterange as $date){
    $arDates[] = $date->format("Y-m-d");
    }
    return $arDates;

  • Just PERFECT!

    thanks a lot!

  • absolute god send, thank you so much

Comments are closed.