Statistics
23384
15
1
11d
Badges
Dependencies

Downloads this Month Latest Stable Version Build Status Scrutinizer Code Climate Coverage Status Dependency Status

What it does?

Filters, calendars, opening hours, activity logs, ... all where since-till appears you can find intervals. Many times it looks like this:

public function foo(DateTimeImmutable $sice, DateTimeImmutable $till) { ... }

In such an implementation you have to repeat chceck $since > $till all over again. Also you have to write your own tooling to work with intervals.

Library php-math-interval brings Value Objects for representation and powerful tooling to easy manipulation.

public function foo(DateTimeImmutableInterval $interval) { ... }

It's awesome!

  • Heavily tested,
  • all object are immutable,
  • code is clean and predictable,
  • interval is modeled as mathematical entity.
composer require achse/php-math-interval

Create an interval

Via factories (most simple):

$interval = DateTimeImmutableIntervalFactory::create(
	new \DateTimeImmutable('2015-10-07T12:00:00+02:00'), 
	Boundary::CLOSED, 
	new \DateTimeImmutable('2015-10-07T14:00:00+02:00'), 
	Boundary::OPENED
);
echo (string)$interval; // [2015-10-07T12:00:00+02:00, 2015-10-07T14:00:00+02:00)

Directly via constructors:

use Achse\Math\Interval\DateTimeImmutable\DateTimeImmutable; // We need object implementing IComparable

$left = new IntegerBoundary(new DateTimeImmutable('2015-10-07T12:00:00+02:00'), Boundary::CLOSED);
$right = new IntegerBoundary(new DateTimeImmutable('2015-10-07T14:00:00+02:00'), Boundary::OPENED);
$interval = new DateTimeImmutableInterval($left, $right);

Parsed from string (used for tests mostly):

$interval = DateTimeImmutableIntervalStringParser::parse('[2015-01-01T05:00:00+02:00, 2015-01-01T10:00:00+02:00)');

Methods

Interval object provides powerful tooling for operations with intervals:

use Achse\Math\Interval\Integer\IntegerIntervalStringParser as Parser;
  • Test if interval contains element
$interval = Parser::parse('[1, 2]');
$interval->isContainingElement(new Integer(2)); // true
$interval->isContainingElement(new Integer(3)); // false
  • Get intersection between two intervals
// (1, 3) ∩ (2, 4) ⟺ (2, 3)
Parser::parse('(1, 3)')->intersection(Parser::parse('(2, 4)')); // (2, 3)
  • Get union of two intervals
// Union of overlapping intervals
Parser::parse('[1, 3]')->union(Parser::parse('[2, 4]')); // ['[1, 4]']
// Union of not overlapping intervals
Parser::parse('[1, 2)')->union(Parser::parse('[3, 4]')); // ['[1, 4]']
// Union of two distant intervals is array of those two intervals 
Parser::parse('[1, 2]')->union(Parser::parse('[3, 4]')); // ['[1, 2], [3, 4]']
  • Diff two intervals
// [1, 4] \ [2, 3]
Parser::parse('[1, 4]')->difference(Parser::parse('[2, 3]')); // ['[1,2)', '(3, 4]']
  • Test if one interval contains the other
// [1, 4] contains [2, 3]
Parser::parse('[1, 4]')->isContaining(Parser::parse('[2, 3]')); // true
// [2, 3] NOT contains [1, 4]
Parser::parse('[2, 3]')->isContaining(Parser::parse('[1, 4]')); // false
  • Does one interval overlap other one from right
Parser::parse('[1, 2]')->isOverlappedFromRightBy(Parser::parse('[2, 3]')); // true
Parser::parse('[2, 3]')->isOverlappedFromRightBy(Parser::parse('[1, 2]')); // false
// (1, 2) ~ [2, 3]
Parser::parse('(1, 2)')->isOverlappedFromRightBy(Parser::parse('[2, 3]')); // false
  • Test if two intervals collides (not empty intersection)
Parser::parse('[2, 3]')->isColliding(Parser::parse('[1, 2]')); // true
Parser::parse('[1, 2]')->isColliding(Parser::parse('(2, 3)')); // false
  • isFollowedByWithPrecision and isFollowedByAtMidnight is available for testing continuity of DateTimeImmutable / DateTime intervals between days.

Available Types

Library contains intervals for those types:

  • Integer - classic int,
  • DateTimeImmutable and DateTime (I strongly advise you to use Immutable only),
  • SingeDayTime - represents "clock-time" of one day. From [00:00:00 one day to 00:00:00) another.

Creating your own type

Interval (its Boundary) can contains any type that implements IComparable, but if you want to have type-hinting you may want to write your own XyInterval and XyBoundary class and probably also Factory classes.

  • 3.0.2 3.0.2

    • Structure and namespaces changed (BC break).
    • API of some interval methods also changes (BC break).
      • Renames methos getIntersection(...) -> just: intersection(...).
      • For example, intersection return empty interval instead of NULL.
    • All objects are strictly immutable (BC break). Methods like setState and setElement from bundary were removed. New withXy methods that returns new object were introduced.
    • Most of classes are now final (BC break).
    • Support for timezones added.
    • DateTime is deprecated in favor of DateTimeInterval (which was added as new type of interval).
    • Dependencies o Nette Packages were dropped.
    • In SingleDate Intervals the "last second of the day" issue was solved. You can use (00:00:00 00:00:00) format - open from both side to create this 24 hours long interval.
  • 3.0.1-rc1 3.0.1-rc1

    Fixies for timezones.

  • 3.0.0-rc1 3.0.0-rc1

  • 2.0.0 2.0.0

  • 1.0.1 Nette 2.4 update dependecies

Is this addon outdated? Did you find an issue? Please report it.

Componette Componette admin@componette.com