Skip to content

Commit 9c59d60

Browse files
committed
Adds intersect() method to Period class
1 parent 5db0316 commit 9c59d60

File tree

4 files changed

+141
-1
lines changed

4 files changed

+141
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
- Adds an option to control transition normalization behavior.
88
- Adds a separator keyword argument to `Interval.in_words()` method.
99
- Adds an alternative formatter.
10-
- Adds support for pytz tzinfo in `instance()` method
10+
- Adds support for pretty much any `tzinfo` instance in the `instance()` method.
11+
- Adds an `intersect()` method to the `Period` class.
1112

1213
### Changed
1314

docs/index.rst

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,3 +1631,59 @@ You can check if a ``Pendulum`` instance is inside a period using the ``in`` key
16311631
16321632
dt in period
16331633
True
1634+
1635+
Intersection
1636+
------------
1637+
1638+
.. versionadded:: 0.6.0
1639+
1640+
The ``intersect()`` method has been added.
1641+
1642+
You can get the intersection of the current ``Period`` instance with others by
1643+
using the ``intersect()`` method.
1644+
1645+
.. code-block:: python
1646+
1647+
import pendulum
1648+
1649+
1650+
monday = pendulum.create(2016, 9, 12)
1651+
wednesday = monday.next(pendulum.WEDNESDAY)
1652+
friday = monday.next(pendulum.FRIDAY)
1653+
saturday = monday.next(pendulum.SATURDAY)
1654+
1655+
period = pendulum.period(monday, friday)
1656+
1657+
period.intersect(pendulum.period(wednesday, saturday))
1658+
# <Period [2016-09-14T00:00:00+00:00 -> 2016-09-16T00:00:00+00:00]>
1659+
1660+
You can also pass multiple period to ``intersect()``.
1661+
1662+
.. code-block:: python
1663+
1664+
import pendulum
1665+
1666+
1667+
monday = pendulum.create(2016, 9, 12)
1668+
wednesday = monday.next(pendulum.WEDNESDAY)
1669+
thursday = monday.next(pendulum.THURSDAY)
1670+
friday = monday.next(pendulum.FRIDAY)
1671+
saturday = monday.next(pendulum.SATURDAY)
1672+
sunday = monday.next(pendulum.SUNDAY)
1673+
1674+
period = pendulum.period(monday, friday)
1675+
wednesday_to_saturday = pendulum.period(wednesday, saturday)
1676+
thursday_to_sunday = pendulum.period(thursday, sunday)
1677+
1678+
period.intersect(
1679+
wednesday_to_saturday,
1680+
thursday_to_sunday
1681+
)
1682+
# <Period [2016-09-15T00:00:00+00:00 -> 2016-09-16T00:00:00+00:00]>
1683+
1684+
If no intersection exists, ``intersect()`` will return ``None``:
1685+
1686+
.. code-block:: python
1687+
1688+
period.intersect(pendulum.period(saturday, sunday))
1689+
None

pendulum/period.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@ def xrange(self, unit):
103103

104104
start = getattr(start, method)(**{unit: 1})
105105

106+
def intersect(self, *periods):
107+
"""
108+
Return the Period intersection of the current Period
109+
and the given periods.
110+
111+
:type periods: tuple of Period
112+
113+
:rtype: Period
114+
"""
115+
start, end = self.start, self.end
116+
has_intersection = False
117+
for period in periods:
118+
if period.end < start or period.start > end:
119+
continue
120+
121+
has_intersection = True
122+
start = max(start, period.start)
123+
end = min(end, period.end)
124+
125+
if not has_intersection:
126+
return None
127+
128+
return self.__class__(start, end)
129+
106130
def as_interval(self):
107131
"""
108132
Return the Period as an Interval.

tests/period_tests/test_intersect.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from pendulum import Period, Pendulum
4+
5+
from .. import AbstractTestCase
6+
7+
8+
class IntersectTestCase(AbstractTestCase):
9+
10+
def test_intersect_included(self):
11+
start = Pendulum(2016, 8, 7)
12+
end = start.add(weeks=1)
13+
p1 = Period(start, end)
14+
intersection = p1.intersect(Period(start.add(days=2), start.add(days=4)))
15+
16+
self.assertPendulum(intersection.start, 2016, 8, 9)
17+
self.assertPendulum(intersection.end, 2016, 8, 11)
18+
19+
def test_intersect_overlap(self):
20+
start = Pendulum(2016, 8, 7)
21+
end = start.add(weeks=1)
22+
p1 = Period(start, end)
23+
intersection = p1.intersect(Period(start.add(days=-2), start.add(days=2)))
24+
25+
self.assertPendulum(intersection.start, 2016, 8, 7)
26+
self.assertPendulum(intersection.end, 2016, 8, 9)
27+
28+
def test_intersect_multiple(self):
29+
start = Pendulum(2016, 8, 7)
30+
end = start.add(weeks=1)
31+
p1 = Period(start, end)
32+
intersection = p1.intersect(
33+
Period(start.add(days=-2), start.add(days=2)),
34+
Period(start.add(days=1), start.add(days=2))
35+
)
36+
37+
self.assertPendulum(intersection.start, 2016, 8, 8)
38+
self.assertPendulum(intersection.end, 2016, 8, 9)
39+
40+
def test_intersect_excluded(self):
41+
start = Pendulum(2016, 8, 7)
42+
end = start.add(weeks=1)
43+
p1 = Period(start, end)
44+
intersection = p1.intersect(
45+
Period(start.add(days=-2), start.add(days=-1))
46+
)
47+
48+
self.assertIsNone(intersection)
49+
50+
def test_intersect_same(self):
51+
start = Pendulum(2016, 8, 7)
52+
end = start.add(weeks=1)
53+
p1 = Period(start, end)
54+
intersection = p1.intersect(
55+
Period(start.copy(), end.copy())
56+
)
57+
58+
self.assertPendulum(intersection.start, 2016, 8, 7)
59+
self.assertPendulum(intersection.end, 2016, 8, 14)

0 commit comments

Comments
 (0)