The Period value object
A Period
instance is a PHP implementation of a bounded datetime interval which consists of:
- two date endpoints hereafter referred to as datepoints. A datepoint is a position in time expressed as a
DateTimeImmutable
object. The starting datepoint is always less than or equal to the ending datepoint. -
its bounds. An included datepoint means that the boundary datepoint itself is included in the interval as well, while an excluded datepoint means that the boundary datepoint is not included in the interval. The package supports included and excluded datepoint, thus, the following bounds are supported:
- included starting datepoint and excluded ending datepoint:
[start, end)
; - included starting datepoint and included ending datepoint :
[start, end]
; - excluded starting datepoint and included ending datepoint :
(start, end]
; - excluded starting datepoint and excluded ending datepoint :
(start, end)
;
- included starting datepoint and excluded ending datepoint:
- the duration between them which correspond to the continuous portion of time between two datepoints expressed as a
DateInterval
object. The duration cannot be negative.
Instantiation
Instantiating a Period
object is done using several named constructors describe below as the default constructor is
made private. Whichever instance used, a Period
instance is always created with the following requirements:
- The
$startDate
represents the starting datepoint. - The
$endDate
represents the ending datepoint. - The
$bounds
represents the interval bounds.
Both $startDate
and $endDate
parameters are datepoints. $endDate
must be greater or equal to $startDate
or the instantiation will throw a Period\IntervalError
.
The $bounds
is a League\Period\Bounds
and only its value are eligible to create a new Period
instance.
Using datepoints
public static Period::fromDate(
DatePoint|DateTimeInterface|string $startDate,
DatePoint|DateTimeInterface|string $endDate,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): Period
If the timezone is important use a DateTimeInterface
object instead of a string. When a string is provided, the timezone information is derived from the underlying system.
$day = Period::fromDate('2012-01-03', Datepoint::fromDateString('2012-02-03'), Bounds::ExcludeAll);
$day->toIso80000('Y-m-d'); //return (2012-01-03, 2012-02-03)
Using timestamp
public static Period::fromTimestamp(
int $startDate,
int $endDate,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): Period
$day = Period::fromTimestamp(10125487, 10158962, Bounds::ExcludeAll);
$day->toIso80000('Y-m-d H:i:s'); //return (1970-04-28 04:0:07, 1970-04-28 13:0:02)
Using a datepoint and a duration
public static Period::after(
DatePoint|DateTimeInterface|string $startDate,
Period|Duration|DateInterval|string $duration,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): Period
public static Period::before(
DatePoint|DateTimeInterface|string $endDate,
Period|Duration|DateInterval|string $duration,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): Period
public static Period::around(
DatePoint|DateTimeInterface|string $midpoint,
Period|Duration|DateInterval|string $duration,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): Period
Period::after
returns aPeriod
object which starts at$startDate
Period::before
returns aPeriod
object which ends at$endDate
Period::around
returns aPeriod
object where the given duration is simultaneously subtracted from and added to the$midpoint
.
Examples
Using Period::after
, Period::around
, Period::before
:
$date = '2012-04-01 08:30:25';
$duration = '1 DAY';
$half_duration = '12 HOURS';
$intervalAfter = Period::after($date, $duration);
$intervalBefore = Period::before($date->add($duration), $duration);
$intervalAfter->equals($intervalBefore); //returns true
$intervalAround = Period::around($date->add($half_duration), $half_duration);
$intervalAround->equals($intervalBefore); //returns true
Using date fields
public static Period::fromDay(int $year, int $month, int $day, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromIsoWeek(int $year, int $week, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromMonth(int $year, int $month, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromQuarter(int $year, int $quarter, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromSemester(int $year, int $semester, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromYear(int $year, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromIsoYear(int $year, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
Examples
$day = Period::fromDay(2012, 1, 3);
$daybis = Period::fromDate('2012-01-03', '2012-01-04');
$day->equals($daybis); //return true;
$day->startDate->format('Y-m-d H:i:s'); //return 2012-01-03 00:00:00
$day->endDate->format('Y-m-d H:i:s'); //return 2012-01-04 00:00:00
Using standardized notation
public static Period::fromIso8601(string $format, string $notation, Bounds $bounds = Bounds::IncludeStartExcludeEnd): Period
public static Period::fromIso80000(string $format, string $notation): Period
public static Period::fromBourbaki(string $format, string $notation): Period
- The
$format
string describes how the date are presented should be a valid string accepted byDateTimeImmutable::createFromFormat
first argument. - The
$notation
string contains the date range as expected by each format.
For better understanding:
- the start datepoint is represented as
{startDate}
- the end datepoint is represented as
{endDate}
- the lower bound is represented as
{lowerBound}
- the upper bound is represented as
{upperBound}
Using ISO 8601 notation
The $notation
should follow the {startDate}/{endDate}
pattern where /
serves as delimiter. Each endpoint should be formatted following the $format
input;
$day = Period::fromIso8601('Y-m-d', '2012-01-03/2012-02-03');
echo $day->toIso80000('Y-m-d H:i:s'), //return [2012-01-03 21:38:22, 2012-02-03 21:38:22)
The previous example can be rewritten as follow:
$day = Period::fromIso8601('Y-m-d', '2012-01-03/02-03'); // the end value is extended (the year is skipped)
echo $day->toIso80000('Y-m-d H:i:s'), //return [2012-01-03 21:38:22, 2012-02-03 21:38:22)
or
$day = Period::fromIso8601('Y-m-d', '2012-01-03/P1M'); // the end value is a duration
echo $day->toIso80000('Y-m-d H:i:s'), //return [2012-01-03 21:38:22, 2012-02-03 21:38:22)
or
$day = Period::fromIso8601('Y-m-d', 'P1M/2012-01-03'); // the start value is a duration
echo $day->toIso80000('Y-m-d H:i:s'), //return [2012-01-03 21:38:22, 2012-02-03 21:38:22)
Using ISO 80000 notation
The $notation
should follow the {lowerbound}{startDate},{endDate}{upperbound}
where ,
serves as delimiter.
Each endpoint should be formatted following the $format
input.
The possible bound values are:
{lowerbound}
can be[
or(
;{upperbound}
can be]
or)
;
$day = Period::fromIso80000('!Y-m-d', '[ 2012-01-03 , 2012-02-03 ]');
echo $day->toIso80000('Y-m-d H:i:s'); // returns [2012-01-03 00:00:00, 2012-02-03 00:00:00]
$day->bounds() === Bounds::IncludeAll;
Using Bourbaki notation
The $notation
should follow the {lowerbound}{startDate},{endDate}{upperbound}
where ,
serves as delimiter.
Each endpoint should be formatted following the $format
input.
The possible bound values are:
{lowerbound}
can be[
or[
;{upperbound}
can be]
or]
;
$day = Period::fromBourbaki('!Y-m-d', '[ 2012-01-03 , 2012-02-03 [');
echo $day->toBourbaki('Y-m-d H:i:s'); // returns [2012-01-03 00:00:00, 2012-02-03 00:00:00[
$day->bounds() === Bounds::IncludeStartExcludeEnd;
Using a DatePeriod object
On PHP8.1
function Period::fromDateRange(
DatePeriod $datePeriod,
Bounds $bounds = Bounds::IncludeStartExcludeEnd
): self
Example
$daterange = new DatePeriod(
new DateTime('2012-08-01'),
new DateInterval('PT1H'),
new DateTime('2012-08-31')
);
$interval = Period::fromDateRange($daterange);
$interval->startDate == $daterange->getStartDate();
$interval->endDate == $daterange->getEndDate();
$dateRange = new DatePeriod('R4/2012-07-01T00:00:00Z/P7D');
$interval = Period::fromDateRange($dateRange);
//throws a TypeError error because $dateRange->getEndDate() returns null
On PHP8.1+
In PHP8.2+ the DatePeriod
exposes full bound information that allow the removal of the
extra optional parameter associated with Period::fromDateRange
.
function Period::fromRange(DatePeriod $datePeriod): self
Example
use League\Period\Bounds;
use League\Period\Period;
$daterange = new DatePeriod(
new DateTime('2012-08-01'),
new DateInterval('PT1H'),
new DateTime('2012-08-31'),
DatePeriod::EXCLUDE_START_DATE | DatePeriod::INCLUDE_END_DATE
);
$interval = Period::fromRange($daterange);
$interval->startDate == $daterange->getStartDate();
$interval->endDate == $daterange->getEndDate();
$interval->bounds === Bounds::ExcludeStartIncludeEnd;
$dateRange = new DatePeriod('R4/2012-07-01T00:00:00Z/P7D');
$interval = Period::fromRange($dateRange);
//throws a TypeError error because $dateRange->getEndDate() returns null