Giter Site home page Giter Site logo

period's Issues

Help about adding new period in a range

I have a problem, I tried to achieve this with this package, but I need help:

These are periods of dates:

$periods = new PeriodCollection(
    Period::make('2019-01-01', '2019-01-02', null, Boundaries::EXCLUDE_NONE),
    Period::make('2019-01-03', '2019-01-05', null, Boundaries::EXCLUDE_NONE),
    Period::make('2019-01-06', '2019-01-13', null, Boundaries::EXCLUDE_NONE),
    Period::make('2019-01-14', '2019-01-20', null, Boundaries::EXCLUDE_NONE),
    Period::make('2019-01-21', '2019-01-25', null, Boundaries::EXCLUDE_NONE),
    Period::make('2019-01-26', '2019-02-10', null, Boundaries::EXCLUDE_NONE)
)

And I want to add this new period:

$c = Period::make('2019-01-03', '2019-01-15', null,Boundaries::EXCLUDE_NONE )

But after calculation was made I want to get these results:

[
        ['start_time' => '2019-01-01', 'end_time' => '2019-01-02'],
        ['start_time' => '2019-01-03', 'end_time' => '2019-01-15'],
        ['start_time' => '2019-01-16', 'end_time' => '2019-01-20'],
        ['start_time' => '2019-01-16', 'end_time' => '2019-01-20'],
        ['start_time' => '2019-01-21', 'end_time' => '2019-01-25'],
        ['start_time' => '2019-01-26', 'end_time' => '2019-02-10'],
]

Could you help to achieve this?

I tried to do this with:

$clearPeriods = $periods->boundaries()->diff($c);
$clearPeriods = $clearPeriods->add($c);

And this is fine when you have only 3 periods, but with multiple, I will have to calculate range of periods, so is there a better way to do this?

Precision - Overlap by X minutes

Would a overlap by X minutes be a good idea?

So this

2020-01-01 15:15:00 would overlap 2020-01-01 15:00:00

if Precision::MINUTE(15) was set, great for calendars I think.

Contains period

Might be just brain-fart, but what is the correct way to see if a period is fully contained within a given other period?

A     [===]
B      [=]

Result: true

A     [===]
B    [==]

Result false

A     [===]
B      [==]

Result true

A     [===]
B     [===]

Result true


A     [===]
B        [===]

Result false

I just see a contains function that accepts a DateTimeInterface. Is it

$c = $a->overlapSingle($b);
return $b->equals($c);

or am I missing something with the precision that could go wrong?

v1 planned ?

Hi ! Your package looks really cool, thanks for it !

This package is still a work in progress.

I'd need something like it in my company's projects. Is there any plan for a first stable release ? If you open some tickets, we could help you for releasing it faster.

touchesWith() does not take precision into consideration

Seems that touchesWith() will always return true if the compared periods are in the same day, even if the times are not really touched and the precision is SECOND.

Example:

$a = Period::make('2018-01-01 06:30:00', '2018-01-01 07:30:00');
$b = Period::make('2018-01-01 09:00:00', '2018-01-01 10:00:00');
$overlap = $a->touchesWith($b);
(true)

This leads to gap() function not detecting the gap for such cases.

Created a PeriodCollection, tried ->overlapAll() but it returns the same collection of periods, not overlaps

I've created the following PeriodCollection:

$dayPeriods = new PeriodCollection();

//period one

$period = Period::make('2022-11-16 21:00:00.0 UTC (+00:00)', '2022-11-16 23:00:00.0 UTC (+00:00)', Precision::MINUTE()); (the start and ends are actually carbon times, but ive made them strings for simplification)
 $dayPeriods = $dayPeriods->add($period);

//period two

$period = Period::make('2022-11-16 22:00:00.0 UTC (+00:00)', '2022-11-16 23:00:00.0 UTC (+00:00)', Precision::MINUTE());
 $dayPeriods = $dayPeriods->add($period);

//period three

$period = Period::make('2022-11-16 22:00:00.0 UTC (+00:00)', '2022-11-16 23:00:00.0 UTC (+00:00)', Precision::MINUTE());
 $dayPeriods = $dayPeriods->add($period);

when I run $overlap = $dayPeriods->overlapAll();

The $overlap is simply the same period collection with exactly the same 3 periods I've defined, it doesn't return the overlaps between the 3 periods inside the period collection.

Any idea why this is happening?

Grab properties of Period object

Hi,

Why are all the properties of the Period object protected?

For example, I want to grab the start & end of a Period object.

$period = Period::make('2021-11-01 08:00:00', '2021-11-01 18:00:00', Precision::MINUTE(), Boundaries::EXCLUDE_ALL());

$period->start returns:

Uncaught Error: Cannot access protected property Spatie\Period\Period::$start 

$period->end returns:

Uncaught Error: Cannot access protected property Spatie\Period\Period::$end 

I tried $period->getStart() as well, which returns:

Uncaught Error: Call to undefined method Spatie\Period\Period::getStart()

Why?

Visualization bugs


ℹ️ Apologies for the brief "issue dump", but my time is currently limited and I wanted to report this already.
Maybe I'll find time to provide details and/or PRs.

Also, thanks for this great package!


I found some bugs in the visualizer. My setup is the following:

use Spatie\Period\Visualizer;
use Spatie\Period\Period;

$v = new Visualizer(['width' => 10]);

$periods = [ /* ... */ ];

echo "\n" . $v->visualize($periods) . "\n";

1. Visualization of less than 2 periods

⚠️ max(): When only one parameter is given, it must be an array

// CASE: No periods
$periods = [];

// CASE: Only one period
$periods = [
  Period::make(now(), now()->addDay())
];

2. Visualization of period spanning no more than one day

⚠️ Division by zero

$periods = [
  Period::make(now(), now()),
  Period::make(now(), now())
];

3. Single-day periods sometimes not rendered

Single-day periods not renderd

$periods = [
     \Spatie\Period\Period::make(now(), now()),
     \Spatie\Period\Period::make(now(), now()->addDay()),
     \Spatie\Period\Period::make(now(), now()),
];
0              
1    [========]
2  

Single-day periods rendered depending on the width

Varying the visualization width seems to affect the outcome.

Assume the following periods:

$periods = [
    Period::make(now(), now()),
    Period::make(now()->addDay(), now()->addDay()),
    Period::make(now()->subDays(38), now()->addDays(2)),
];

Width: 50 (all periods rendered)

$v = new Visualizer(['width' => 50]);
0                                                   =  
1                                                    = 
2    [================================================]

Width: 60 (one period "gone")

$v = new Visualizer(['width' => 60]);
0                                                                
1                                                              = 
2    [==========================================================]

Check if Period overlaps any Period's within a PeriodCollection

Is there a way to check if a single Period overlaps any other Period within a PeriodCollection, without having to manually loop over each collection item?

Sorry for asking this question as a issue, is there a discord chat or anything similar regarding this package?

Overlap percentage

Is it possible to calculate a percentage of coverage for one period with second?

Periods without end

This might seem like an edge case, but it's one we have to deal with often: periods that never end. It would be nice if this package supported them.

[2.0] discussion

With the change made to length() in #21, we're required to tag a new major version. So let's discuss what else we want to add.

Get all overlapsed dates from collection

Hello,
I need to get a range of overlapping dates from a collection.

Maybe I missed something in the docs but I can not find something like:

$collection = new PeriodCollection(
    Period::make('2018-01-01', '2018-01-05'),
    Period::make('2018-01-10', '2018-01-15'),
    Period::make('2018-01-20', '2018-01-25'),
    Period::make('2018-01-30', '2018-01-31')
);

$gaps = $collection->gaps();

But getting:
$overlaps = $collection->overlaps();
instead of gaps

Would that be possible ?

Best regards

PeriodCollection with null element after diff

Hi, if I calculate diff between two not intersected periods and try to loop:
Return value of Spatie\Period\PeriodCollection::current() must be an instance of Spatie\Period\Period, null returned

$dayPeriod = Period::make('2019-02-01 15:00:00', '2019-02-01 20:00:00', Precision::MINUTE);
$events = new PeriodCollection(
    // $dayPeriod does not contain this event
    Period::make('2019-02-01 10:00:00', '2019-02-01 14:00:00', Precision::MINUTE)
);
$periods = $dayPeriod->diff(...$events);

foreach ($periods as $period) { //throw TypeError
    var_dump($period);
}

Exception thrown when getting gaps for a 0-length period with excluded boundaries

Description

If you try and get the gaps for a period collection containing a single 0-width period, an exception is thrown if any boundaries are excluded - start, end, or all

Replication

$period = Period::make(
   start: '2023-07-26 07:00:00',
   end: '2023-07-26 07:00:00',
   boundaries: Boundaries::EXCLUDE_END()
);

PeriodCollection::make($period)->gaps();

Trace

The end time `2023-07-25 00:00:00` is before the start time `2023-07-26 00:00:00`. {"userId":72,"exception":"[object] (Spatie\\Period\\Exceptions\\InvalidPeriod(code: 0): The end time `2023-07-25 00:00:00` is before the start time `2023-07-26 00:00:00`. at C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\Exceptions\\InvalidPeriod.php:12)
[stacktrace]
#0 C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\Period.php(37): Spatie\\Period\\Exceptions\\InvalidPeriod::endBeforeStart(Object(DateTimeImmutable), Object(DateTimeImmutable))
#1 C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\PeriodFactory.php(53): Spatie\\Period\\Period->__construct(Object(DateTimeImmutable), Object(DateTimeImmutable), Object(Spatie\\Period\\Precision), Object(Spatie\\Period\\Boundaries))
#2 C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\Period.php(54): Spatie\\Period\\PeriodFactory::make('Spatie\\\\Period\\\\P...', Object(DateTimeImmutable), Object(DateTimeImmutable), Object(Spatie\\Period\\Precision), Object(Spatie\\Period\\Boundaries), NULL)
#3 C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\PeriodCollection.php(68): Spatie\\Period\\Period::make(Object(DateTimeImmutable), Object(DateTimeImmutable), Object(Spatie\\Period\\Precision), Object(Spatie\\Period\\Boundaries))
#4 C:\\inetpub\\wwwroot\\xxxx\\vendor\\spatie\\period\\src\\PeriodCollection.php(74): Spatie\\Period\\PeriodCollection->boundaries()
#5 C:\\inetpub\\wwwroot\\xxxx\\app\\Http\\Controllers\\yyyy.php(66): Spatie\\Period\\PeriodCollection->gaps()

Question: Check per 5 minute interval

Hi,

First of all this is a great package! I've been playing with it and I was wondering if it's possible to check per 5 or 10 minute interval instead of per minute. This limits the numbers of checks for a certain time period if it spans a longer time frame.

Kind regards,

Rogier

Returns PeriodCollection with null element

When I try to use PeriodCollection's function isEmpty this return false, but when i dump

screen shot 2019-01-08 at 12 20 40 pm

I have that:

screen shot 2019-01-08 at 12 20 32 pm

So method isEmpty works not right, because array only with one null element.

Here in my code:
screen shot 2019-01-08 at 12 25 25 pm

Can you fix this issue?

Period roundDate() does not keep date's timezone

When creating a new Period, with timezoned start, end, the period object ends up with start, end in UTC always.

  $start = new \DateTimeImmutable('2000-01-01', new \DateTimeZone('Europe/London'));
  $end = new \DateTimeImmutable('2000-02-01', new \DateTimeZone('Europe/London'));
  $period = new \Spatie\Period\Period($start, $end);
  var_dump($period->getStart());

result:

object(DateTimeImmutable)#3257 (3) { ["date"]=> string(26) "2000-01-01 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }

Suggestion solution to change this:

implode(' ', [$year, $month, $day, $hour, $minute, $second])

to this:

 implode(' ', [$year, $month, $day, $hour, $minute, $second]), $date->getTimezone()

Visualizer cause error when it have one period

PHP 8.1
When $periods contains one period

        $visualizer = new Visualizer(["width" => 120]);
        $visualizer->visualize($periods);

This cause error in the selected line, because max function argument is integer.
In this line not need spread operator ..., because that function can works with arrays.


class Visualizer {
     ...
    public function visualize(array $blocks): string
    {
        $matrix = $this->matrix($blocks);

>>>>>>> $nameLength = max(...array_map('strlen', array_keys($matrix)));

        $lines = [];

        foreach ($matrix as $name => $row) {
            $lines[] = vsprintf('%s    %s', [
                str_pad($name, $nameLength, ' '),
                $this->toBars($row),
            ]);
        }

        return implode("\n", $lines);
    }
    ...
}

Multiple gaps support

We want to calculate multiple gaps like so:

/*
 * A                   [====]
 * B                               [========]
 * C         [=====]
 * D                                             [====]
 *
 * GAPS             [=]      [====]          [==]
 */

The method should be called gaps, accept n-amount of periods and calculate all the gaps.

This can be done by creating a period with the most left and right boundaries, and diffing that period against all others.

Including or excluding boundaries

Right now, the boundaries of a period are always included in calculations. We should have a discussion about what the desired default behaviour should be, whether we want to make this behaviour configurable, and how.

Hours, minutes and seconds are reset from provided period

Hello,

When creating a Period like this:

Period::make('10:00', '11:00', Precision::MINUTE(), Boundaries::EXCLUDE_END(), 'H:i');

Hours, minutes and seconds are cleared in the PeriodFactory.php lines 107-109:

if (! str_contains($format, ' ')) {
    $dateTime = $dateTime->setTime(0, 0, 0);
}

So this is wrong:

$period1 = Period::make('10:00', '11:00', Precision::MINUTE(), Boundaries::EXCLUDE_END(), 'H:i');
$period2 = Period::make('10:00', '11:00', Precision::MINUTE(), Boundaries::EXCLUDE_END(), 'H:i');

$period1->overlapsWith($period2); // false

Is there a reason why times are being cleared? Could we not do it depending on the precision instead of expecting a date format + time format?

Temporal (or not) fix:

Period::make(Date::now()->setTimeFromTimeString('10:00'), Date::now()->setTimeFromTimeString('11:00'), Precision::MINUTE(), Boundaries::EXCLUDE_END());

Does this package only compares the dates, or does it also use the timestamp?

Not sure based on the documentation. Does this package also work with time stamps, or does it only compare the dates? The examples only show dates, but since the period accepts DateTime objects, it might also work with time.

For example, would this work?

$a = Period::make('2020-01-01 12:00:00', '2020-01-01 14:00:00');
$a = Period::make('2020-01-01 16:00:00', '2020-01-01 18:00:00');

$overlap = $a->gap($b); // Period('2020-01-01 14:00:00', '2020-01-01 16:00:00')

Thanks!

Possible bug in PeriodCollection gaps()

Given two equal periods with boundaries:

$collection = new PeriodCollection(
    Period::make('2018-01-01', '2018-01-03', null, Boundaries::EXCLUDE_END),
    Period::make('2018-01-01', '2018-01-03', null, Boundaries::EXCLUDE_END)
);

$gaps = $collection->gaps();

I expected gaps to return 0 periods, but I get 1 period instead:

// $gaps->count() == 1
// $period->getStart() == '2018-01-03'
// $period->getEnd() == '2018-01-03'

Is this expected?

Length with precision

The length method always returns the length in days, instead of the precision of the period. An oversight by me. We're going to fix it and release a new major version.

My suggestion is the following:

  • Change length to return the length with the precision of that period,
  • Add helper methods lengthInDays, lengthInYears,...

One more thing I'm wondering about: should length return a simple integer, or should it return some kind of PeriodLength object, which also contains the precision?

Getting the periods that are not overlapped

Hi there,

I've just picked up this package. It seems pretty good. I've ran into an issue where I want the opposite of overlap.

overlap rightly returns what time out of a list of periods overlap with the current period. I want to be able to get what time is not overlapped.

See visual examples below 👇

Overlap
/*
 * A       [========]
 * B                    [==]
 * C                            [=====]
 * CURRENT        [===============]
 *
 * OVERLAP        [=]   [==]    [=]
 */
Clear(?)
/*
 * A       [========]
 * B                    [==]
 * C                            [=====]
 * CURRENT        [===============]
 *
 * CLEAR  [=======]                [===]
 */

What would be the best way to do this, if already implemented?

Improve PHP 8.1.0 support...

There is a warning if use strings for dates:

$period = Period::make('2021-01-01', '2021-01-31');


PHP Deprecated:  str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in ****/vendor/spatie/period/src/PeriodFactory.php on line 122

[2.0] Configure Date class to use

Hi guys,

Periods are always immutable, there's never the worry about your input dates being changed.

This seems a bit too much opinionated to me for a Period library.

I think it should be an agnostic DateTimeInterface in typings (so stay flexible with inheritance ing PHP < 7.4) as in https://github.com/spatie/opening-hours

And I can propose a PR to have a class customization like in CarbonPeriod:
https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/CarbonPeriod.php#L228

It means you would have DateTimeImmutable as the default class, but other classes could be set as long as they implements DateTimeInterface so users could choose if getStart() and similar methods would return DateTimeImmutable, DateTime, Carbon, Chronos etc. objects.

CarbonPeriod has both an IMMUTABLE flag option to switch Carbon/CarbonImmutable and a ->setDateClass() method to switch to any DateTimeInterface sub-class. And any class that extends CarbonPeriod can easily change the default class by overriding the property default value.

Are you interested in a similar way to choose the date class for Spatie\Period\Period?

Add/subtract collections..

I've just picked this library up and it's proving really useful. Could you tell me if/how it's possible to join periods? As in if I add a period to a period/collection, it would create a flattened/normalized collection of the two.

/*
 * A              [======]
 * B                   [=======]
 *
 * JOIN           [============]
 *
 * C         [===]
 * D                          [===]
 *
 * JOIN      [===]            [===]
 */

$a = Period::make('2018-01-01', '2018-01-15');
$b = Period::make('2018-01-10', '2018-01-25');

$joinCollection = $a->join($b);

$c = Period::make('2018-01-01', '2018-01-05');
$d = Period::make('2018-01-10', '2018-01-15');

$joinCollection = $c->join($d);

If I add a period to a collection it just holds the period even it they overlap.

I suspect it's a technique that I haven't figured out. A pointer would be very welcome.

Many thanks,

Jerry

Calculate total length of Collection

Following on from Length with precision and the 2.0 discussion I think it would be useful to be able to call ->length() on a PeriodCollection (with an optional precision) to return the total duration of all the periods contained within, combined. This could be aliased to duration.

Proposed

$collection = new PeriodCollection(
    Period::make('2019-01-01', '2019-01-08'),
    Period::make('2019-02-01', '2019-02-08'),
    Period::make('2019-03-08', '2019-03-15')
);

$collection->length(); // 24 (as the precision of the periods' is DAY
$collection->duration; // 24 as this is another name for length
$collection->length(Precision::HOUR); // 576 (24 days of 24 hours)

Current

This can be achieved by using a Laravel Collection and passing a closure to the sum method but I think this should be part of this package.

$collection = collect([
    Period::make('2019-01-01', '2019-01-08', Precision::HOUR),
    Period::make('2019-02-01', '2019-02-08', Precision::HOUR),
    Period::make('2019-03-08', '2019-03-15', Precision::HOUR)
]);

$collection->sum(function ($p) {
    return $p->length();
}); // 24 (as this does not yet take into account the precision)

Documentation typo

The first example:
$period = Period::make('2021-01-01', '2020-01-31');

Should be:
$period = Period::make('2021-01-01', '2021-01-31');

Ie - the end date was before the start date

Compare multiple periods with precision

Hello. I get Exception\CannotComparePeriods when I use precision parameter with comparing multiple periods. Examples:

// Diff between multiple periods
$a = Period::make('2018-01-05 00:00:00', '2018-01-10 00:00:00', Precision::MINUTE);
$b = Period::make('2018-01-15 00:00:00', '2018-03-01 00:00:00', Precision::MINUTE);
$c = Period::make('2018-01-01 00:00:00', '2018-01-31 00:00:00', Precision::MINUTE);
$diff = $c->diff($a, $b);

or

// Overlap with all periods
$a = Period::make('2018-01-01 00:00:00', '2018-01-31 00:00:00', Precision::MINUTE);
$b = Period::make('2018-01-10 00:00:00', '2018-01-15 00:00:00', Precision::MINUTE);
$c = Period::make('2018-01-10 00:00:00', '2018-01-31 00:00:00', Precision::MINUTE);
$overlap = $a->overlapAll($b, $c);

Precision::fromString incompatible to Boundaries::fromString

When trying to create a new period, I get a fatal error:

Fatal error: Declaration of Spatie\Period\Precision::fromString(string $string): Spatie\Period\Precision must be compatible with Spatie\Period\Boundaries::fromString(string $startBoundary, string $endBoundary)

The Period creation is done with the following code:
Period::make(new \DateTimeImmutable('now'), new \DateTimeImmutable('now +1 day'), Precision::SECOND());

Am i missing something here?

Is this package suitable for appointment systems?

Hi,

I had some questions regarding the Spatie/Period composer package.

Is this package suitable to use for an appointment system?

I know you can generate a list of periods using the PeriodCollection class, so if I add all the existing appointments of a single day to a PeriodCollection, is there a way for me to search for available periods/time slots, using gaps I guess?

Really looking forward to your response.

Thanks in advance,

Amir

Scheduling "things"

I'm using https://github.com/spatie/period for complex calendar operations. It's great, but it would be better if I could attach "things". For example, schedule a "vacation" and then be able to retrieve that vacation or vacations from Period or PeriodCollection. That way I would see which of my vacations are overlapping. I realize the inverse is possible: my vacation hasa Period. However that doesn't flow forward into the PeriodCollection of Overlaps... Which vacations are overlapping?

Period Collection to accept array of periods

I think it would be really nice if we could pass an array or collection of periods into a Period Collection.

Rather than having to do

$collection = new PeriodCollection(
    Period::make('2018-01-01', '2018-01-05'),
    Period::make('2018-01-10', '2018-01-15'),
    Period::make('2018-01-20', '2018-01-25'),
    Period::make('2018-01-30', '2018-01-31')
);

We could do something like this:

$event_periods = $events->map(function($event) {
     return Period::make($event->start, $event->end);
});
$event_period_collection = new PeriodCollection($event_periods);

Let me know if that doesn't make sense.

Overlap all (n^2)

/*
 * A       [========]
 * B             [==]
 * C                                         [=====]
 * D                                         [===============]
 *
 * OVERLAP       [==]                        [=====]
 */

how would one combine the given overlap,diff,and gap functions to get
such collection as described in the graph above?

[2.0] minimum PHP requirement

I'd like to bump the PHP requirement with the next major release. Ideally I'd want it to be 7.3. 7.2 should in any case be the minimum.

How do we feel about this?

Support for Eloquent

Hello, thank you for this package, really useful! I wonder if you are willing to support eloquent scopes to perform similar results? My use case would be to check if a booking is overlapping a given period.

return new class extends Migration 
{
  public function up(): void
  {
    Schema::create("bookings", function (Blueprint $table) {
      $table->id();
      $table->dateTime("starts_at");
      $table->dateTime("ends_at");
      $table->timestamps();
    });
  }
};
use App\Models\Booking;
use Spatie\Period\Period;

$period = Period::make("2024-01-24 10:00:00", "2024-01-24 19:00:00");

$bookings = Booking::overlapping($period)->get();

[2.0] Period::overlap methods

Period has three ways of overlapping:

Period::overlapSingle(Period $period): ?Period
Period::overlap(Period ...$periods): PeriodCollection
Period::overlapAll(Period ...$periods): ?Period

The naming here is very confusing, and I'd like this to improved with v2.

Period::overlapSingle will determine the overlap between two periods, and return a single Period or null.

A        [===========]
B            [============]

OVERLAP      [=======]

The more obvious name would simply be overlap.

Period::overlap allows for overlapping multiple periods on each other:

A       [========]
B                   [==]
C                           [=====]
D              [===============]

OVERLAP        [=]   [==]   [==]

This name is confusing, I can think of two improvements:

  • Period::overlapAny(Period ...$periods)
  • PeriodCollection::overlapAny()

They would have a subtle difference: Period::overlapAny(Period ...$periods) would compare each period to the "master period", while PeriodCollection::overlapAny() would compare all periods in the collection to each other.

Period::overlapAll is also confusing, it does the following:

A              [============]
B                   [==]
C                   [=======]

OVERLAP             [==]

I believe the correct solution would be to move this functionality to PeriodCollection::overlapAll() — although I think we should come up with a better name.

Again we could keep the shorthand on Period.

Another issue with Period::overlapAll is that it can only return one period, while this could also be possible with collection

COLLECTION A              [===============================]
COLLECTION B                   [==]             [=======]
COLLECTION C                   [=======]      [======]

COLLECTION OVERLAP             [==]             [====]

ISO-8601 time interval support

It'd be nice to be able to translate to/from the ISO-8601 time interval standard.

I'm surprised how little support there is in PHP for this as it's a nice, concise way of expressing a period of time. thephpleague's package has partial support but doesn't allow for using durations in the start (P1M/2022-02-01T00:00:00Z) or end (2022-01-01T00:00:00Z/P1M) nor for using a condensed datetime for the end such as 2022-01-01T00:00:00Z/15 which expands to 2022-01-01T00:00:00Z/2022-01-15T00:00:00Z.

The standard doesn't allow for transferring bounds but they could be defined in a parameter.

Add debug helper

According to the first example of the doc :

$a = Period::make('2018-01-01', '2018-01-31');
$b = Period::make('2018-02-10', '2018-02-20');
$c = Period::make('2018-03-01', '2018-03-31');
$current = Period::make('2018-01-20', '2018-03-10');
$overlaps = $current->overlap($a, $b, $c);

Why not implementing __string() that would make a nice representation of the result like in your doc :

echo $overlaps; // ouput:

A       [========]
B                    [==]
C                            [=====]
CURRENT        [===============]
OVERLAP        [=]   [==]    [=]

It could be a very convenient way for debugging.

Why does diff sometimes return a gap?

I interpreted the Period::diff function to be a "subtraction". So I can remove, say, a week from a month (whether or not they become 2 split periods). However, I noticed a special case in code that confused me and seems to do something else entirely: it returns a gap.

Right at the beginning of the function it checks whether the input was a single, non-overlapping period. In that case it returns the gap between them! But why is that? It's not consistent with the way diffSingle works (which is called in every other scenario). It seems to be an inconsistency.

In fact, diffSingle has a (conflicting) special case: it returns both of the periods. That makes no sense to me whatsoever. Here's some code:

// Period for entire month of January.
$january = new Period(
    new DateTimeImmutable('2021-01-01'),
    new DateTimeImmutable('2021-02-01'),
    Precision::SECOND,
    Boundaries::EXCLUDE_END
);

// Remove something (in this case nothing needs to be removed).
$firstPartOfJanuary = $january->diff(new Period(
    new DateTimeImmutable('2021-03-01'),
    new DateTimeImmutable('2021-04-01'),
    Precision::SECOND,
    Boundaries::EXCLUDE_END
))[0];

// Expected to be January. It turns out to be Februari!
$firstPartOfJanuary->getStart()->format('c'); // 2021-02-01T00:00:00+01:00
$firstPartOfJanuary->getEnd()->format('c');   // 2021-02-28T23:59:59+01:00

/** Doing the exact same thing with diffSingle. */

$partsOfJanuary = $january->diffSingle(new Period(
    new DateTimeImmutable('2021-03-01'),
    new DateTimeImmutable('2021-04-01'),
    Precision::SECOND,
    Boundaries::EXCLUDE_END
));

// Expected to be January, and it is. But it also includes March!
$partsOfJanuary[0]->getStart()->format('c'); // 2021-01-01T00:00:00+01:00
$partsOfJanuary[0]->getEnd()->format('c');   // 2021-02-01T00:00:00+01:00
$partsOfJanuary[1]->getStart()->format('c'); // 2021-03-01T00:00:00+01:00
$partsOfJanuary[1]->getEnd()->format('c');   // 2021-04-01T00:00:00+01:00

/** Doing the exact same thing, but remove a second, bogus, period as well. */

$partsOfJanuary = $january->diff(
    new Period(
        new DateTimeImmutable('2021-03-01'),
        new DateTimeImmutable('2021-04-01'),
        Precision::SECOND,
        Boundaries::EXCLUDE_END
    ),
    new Period(
        new DateTimeImmutable('9998-01-01'),
        new DateTimeImmutable('9999-01-01'),
        Precision::SECOND,
        Boundaries::EXCLUDE_END
    )
)[0];

// Expected to be January, and January *only*. And it is!
$partsOfJanuary[0]->getStart()->format('c'); // 2021-01-01T00:00:00+01:00
$partsOfJanuary[0]->getEnd()->format('c');   // 2021-02-01T00:00:00+01:00
count($partsOfJanuary);                      // 1

Add periods to a PeriodCollection?

Hello,

Probably stupid, but I can't. How to fill the PeriodCollection via an array of data:

                $collection = new PeriodCollection();
                foreach ($this->array_events as $event) {
                    $collection->Period::make($event['event_start'], $event['event_ended'], Precision::MINUTE());
                }
                $gaps = $collection->gaps();

It doesn't work, error:
Undefined property: Spatie\Period\PeriodCollection::$Period

thank you

Add a Period->coversDate method

I have use cases for this library but what prevents me from using it is a convenient Period->coversDate method that receives a DateTime object and two mode information for whether the start/end of the period are included or excluded. The mode may also be be combined to a single parameter.

Would this be possible and within the scope of this library?

Get available time slots between periods

Is this package sufficient enough to calculate timeslots between certain periods?

Let's say my business opens from 08:00 to 18:00 on a specific day, with a work break at 13:00 to 14:00.

This makes the following periods:

Period::make('2020-07-27 08:00', '2020-07-27 13:00', Precision::MINUTE);
Period::make('2020-07-27 14:00', '2020-07-27 18:00', Precision::MINUTE);

Now having those periods, how would I be able to generate an array of (e.g.) 15 minutes timeslots, that are available/gasps?

Carry over exclusion

At first I thought this was an off by one error, but it's not quite. It's just a nasty gotcha because the boundary exclusions are not carried over. Here's code with the problem.

// Period for entire month of January.
$january = new Period(
    new DateTimeImmutable('2021-01-01'),
    new DateTimeImmutable('2021-02-01'),
    Precision::SECOND,
    Boundaries::EXCLUDE_END
);

// Remove something.
$firstPartOfJanuary = $january->diff(new Period(
    new DateTimeImmutable('2021-01-22'),
    new DateTimeImmutable('2021-02-01'),
    Precision::SECOND,
    Boundaries::EXCLUDE_END
))[0];

// Now I'm expecting end to be 2021-01-22 0:00. It isn't:
$firstPartOfJanuary->getEnd()->format('c'); // 2021-01-21T23:59:59+01:00

// That is because:
$firstPartOfJanuary->endExcluded(); // false

I'm expecting the end to be excluded, as both input periods have EXCLUDE_END...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.