DatePeriod 类
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
简介
DatePeriod 类表示一个时间周期。
一个时间周期可以用来在给定的一段时间之内, 以一定的时间间隔进行迭代。
类摘要
class DatePeriod
implements
Traversable {
/* 常量 */
/* 属性 */
/* 方法 */
public __construct(
DateTimeInterface
DateInterval
int
int
)
DateTimeInterface
$start
,DateInterval
$interval
,int
$recurrences
,int
$options
= 0)
public __construct(
DateTimeInterface
DateInterval
DateTimeInterface
int
)
}DateTimeInterface
$start
,DateInterval
$interval
,DateTimeInterface
$end
,int
$options
= 0)
预定义常量
DatePeriod::EXCLUDE_START_DATE
-
在 DatePeriod::__construct() 构造函数中使用,表示不包含开始时间。
属性
- recurrences
-
如果通过显式的传入
$recurrences
来创建的 DatePeriod 实例, 那么这个参数表示循环次数。 参见:DatePeriod::getRecurrences()。 - include_start_date
-
在循环过程中,是否包含开始时间。
- start
-
时间周期的开始时间。
- current
-
表示在时间周期内迭代的时候,当前的时间。
- end
-
时间周期的结束时间。
- interval
-
ISO 8601 格式的间隔。
更新日志
版本 | 说明 |
---|---|
5.3.27, 5.4.17 | 公开以下属性:recurrences, include_start_date,start, current,end 和 interval。 |
目录
- DatePeriod::__construct — Creates a new DatePeriod object
- DatePeriod::getDateInterval — Gets the interval
- DatePeriod::getEndDate — Gets the end date
- DatePeriod::getRecurrences — Gets the number of recurrences
- DatePeriod::getStartDate — Gets the start date

User Contributed Notes 11 notes
josh dot love at verizon dot net ¶
9 years ago
Just an example to include the end date using the DateTime method 'modify'
<?php
$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>";
}
?>
logos-php at kith dot org ¶
9 years ago
Thanks much to those of you who supplied sample code; that helps a lot.
I wanted to mention another thing that helped me: when you do that foreach ( $period as $dt ), the $dt values are DateTime objects.
That may be obvious to those of you with more experience, but I wasn't sure until I looked it up on Stack Overflow. So I figured it was worth posting here to help others like me who might've been confused or uncertain.
mail at pascalhofmann dot de ¶
5 years ago
When looping over a DatePeriod object, the returned objects always implement DateTimeInterface. The exact type returned depends on how the DatePeriod was created. If $start was a DateTimeImmutable, the objects returned will be of type DateTimeImmutable. If a DateTime object was used, the objects returned will be of type DateTime.
Joey ¶
2 years ago
This class isn't always intuitive. End is exclusive. All you need to do to include it is to add a second (the smallest amount).
Microseconds are ignored.
php -r '
/***/$p1d = new DateInterval("P1D");
/***/$b = (new DateTime())->setTime(0, 0, 0, 0);
/***/$a = (clone $b)->sub($p1d);
/***/$f = function(DateTime $b)use($a, $p1d):void {
/***//***/$p = new DatePeriod($a, $p1d, $b);
/***//***/$i = iterator_to_array($p);
/***//***/print_r([$i[0], end($i), $a, $b]);
/***/};
/***/$f($b);
/***/$f($b->setTime(0, 0, 0, 1));
/***/$f($b->setTime(0, 0, 1, 0));
'
It is a sign of the end times.
php at karlsruler dot de ¶
6 years ago
The iterator seems to check the time as well, it excludes the end element if its time is 00:00:00. So the slightly safer version (to compare it against joshs suggestion) is to use $date->setTime(23, 59, 59) instead of $date->modify("+1 day").
mike at saymikeo dot com ¶
5 years ago
Calculating business days can be cumbersome. Here is an iterator for handling business days. Usage examples below for adding # of business days and calculating how many business days between two dates.
Here is the iterator class
https://gist.github.com/styks1987/29dd0f6a68e3b07ba70fec18f732eb86
Usage
Counting # of Business Days between two dates
<?php
function countBusinessDays($start, $stop)
{
if($start > $stop){
$tmpStart = clone $start;
$start = clone $stop;
$stop = clone $tmpStart;
}
// Adding the time to the end date will include it
$period = new \DatePeriod($start->setTime(0,0,0), new \DateInterval('P1D'), $stop->setTime(23,59,59), \DatePeriod::EXCLUDE_START_DATE);
$periodIterator = new BusinessDayPeriodIterator($period);
$businessDays = 0;
while($periodIterator->valid()){
// If we run into a weekend, don't count it
if(!$periodIterator->isWeekend()){
$businessDays++;
}
$periodIterator->next();
}
return $businessDays;
}
?>
Add # of business days
<?php
function addBusinessDays(\DateTime $startDateTime, $daysToAdd)
{
$endDateTime = clone $startDateTime;
$endDateTime->add(new \DateInterval('P' . $daysToAdd . 'D'))->setTime(23,59,59);
$period = new \DatePeriod($startDateTime, new \DateInterval('P1D'), $endDateTime);
$periodIterator = new BusinessDayPeriodIterator($period);
$adjustedEndingDate = clone $startDateTime;
while($periodIterator->valid()){
$adjustedEndingDate = $periodIterator->current();
// If we run into a weekend, extend our days
if($periodIterator->isWeekend()){
$periodIterator->extend();
}
$periodIterator->next();
}
return $adjustedEndingDate;
}
?>
jkaatz at gmx dot de ¶
12 years ago
Nice example from PHP Spring Conference (thanks to Johannes Schlüter and David Zülke)
<?php
$begin = new DateTime( '2007-12-31' );
$end = new DateTime( '2009-12-31 23:59:59' );
$interval = DateInterval::createFromDateString('last thursday of next month');
$period = new DatePeriod($begin, $interval, $end, DatePeriod::EXCLUDE_START_DATE);
foreach ( $period as $dt )
echo $dt->format( "l Y-m-d H:i:s\n" );
?>
DateInterval specs could be found at http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
patrick at adrichem dot nu ¶
8 years ago
DatePeriod is not compatible with negative intervals.
To do so you can simply use DateInterval and loop through it yourself like this: (not start should be ahead of end if you use a negative interval
class DateRange extends ArrayIterator
{
protected $oDate = null;
protected $oStartDate = null;
protected $oEndDate = null;
protected $oInterval = null;
public function __construct( DateTime $oStartDate, DateTime $oEndDate, DateInterval $oInterval = null )
{
$this->oStartDate = $oStartDate;
$this->oDate = clone $oStartDate;
$this->oEndDate = $oEndDate;
$this->oInterval = $oInterval;
}
public function next()
{
$this->oDate->add($this->oInterval);
return $this->oDate;
}
public function current()
{
return $this->oDate;
}
public function valid()
{
if ($this->oStartDate > $this->oEndDate)
{
return $this->oDate >= $this->oEndDate;
}
return $this->oDate <= $this->oEndDate;
}
}
$oRange = new DateRange(new DateTime("2013-10-01"), new DateTime("2013-01-01"), DateInterval::createFromDateString("-1 month") );
foreach ($oRange as $oDate)
{
echo $oDate->format("Y-m-d") . "<br />";
}
Memori ¶
11 years ago
If you want to include the end-date, add one day to it:
<?php
$startDate = new DateTime();
$endDate = new DateTime();
$startDateInt = new DateInterval( "P1Y" );
$endDateInt = new DateInterval( "P1D" );
$startDate->sub( $startDateInt );
$endDate->add( $endDateInt );
$periodInt = new DateInterval( "P1M" );
$period = new DatePeriod( $startDate, $periodInt, $endDate );
// At februari 2011:
// $period = (8,9,10,11,12,1,2)
?>
johnzenith71(at)gmail.com ¶
3 years ago
An extra piece of information on how to use the (modify method) to easily get date ranges:
<?php
$subscription_start_date = new DateTime( 'now' );
// Modify the $subscription_start_date date value to required date range,
// this could be in days or months depending on how your application is designed
// Days
$subscription_expiration = $subscription_start_date->modify( '+60 days' );
echo $subscription_expiration->format( 'Y-m-d' ) . "\n";
// Months
$subscription_expiration = $subscription_start_date->modify( '+2 Months' );
echo $subscription_expiration->format( 'Y-m-d' ) . "\n";
// Or even in years
$subscription_expiration = $subscription_start_date->modify( '+2 years' );
echo $subscription_expiration->format( 'Y-m-d' ) . "\n";
?>
joseph dot cardwell at jbcwebservices dot com ¶
4 years ago
As someone noted, at least in 7.2, dates with time 0 are excluded from the start and end.
To get a regular span of dates I ended up with:
$dates = new DatePeriod(
( new DateTime($date_start) )->setTime(0,0,1),
new DateInterval('P1D'),
( new DateTime($date_end) )->setTime(0,0,1)
);