spatie / period Goto Github PK
View Code? Open in Web Editor NEWComplex period comparisons
Home Page: https://spatie.be/open-source
License: MIT License
Complex period comparisons
Home Page: https://spatie.be/open-source
License: MIT License
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?
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.
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?
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.
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.
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?
The 2.0.0 released has been done. But the readme still contains that sentence:
This package is still a work in progress.
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?
ℹ️ 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";
⚠️ 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())
];
⚠️ Division by zero
$periods = [
Period::make(now(), now()),
Period::make(now(), now())
];
$periods = [
\Spatie\Period\Period::make(now(), now()),
\Spatie\Period\Period::make(now(), now()->addDay()),
\Spatie\Period\Period::make(now(), now()),
];
0 1 [========] 2
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 [==========================================================]
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?
Is it possible to calculate a percentage of coverage for one period with second?
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.
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.
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
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);
}
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
$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();
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()
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
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:
Line 527 in 14e56b6
to this:
implode(' ', [$year, $month, $day, $hour, $minute, $second]), $date->getTimezone()
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);
}
...
}
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.
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.
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());
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!
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?
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:
length
to return the length with the precision of that period,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?
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 👇
/*
* A [========]
* B [==]
* C [=====]
* CURRENT [===============]
*
* OVERLAP [=] [==] [=]
*/
/*
* A [========]
* B [==]
* C [=====]
* CURRENT [===============]
*
* CLEAR [=======] [===]
*/
What would be the best way to do this, if already implemented?
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
Period::make
will reset the time to 00:00:00, we should also support other times.
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
?
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
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)
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
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);
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?
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
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?
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.
/*
* 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?
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?
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();
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 [==] [====]
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.
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.
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
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
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?
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?
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...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.