Skip to content

Commit db1507c

Browse files
committed
Improves Period class
1 parent caaabe8 commit db1507c

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

docs/index.rst

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,3 +1249,56 @@ you set the ``absolute`` keyword argument to ``True``:
12491249
12501250
period.in_weekend_days()
12511251
10
1252+
1253+
Range
1254+
-----
1255+
1256+
If you want to iterate over a period, you can use the ``range()`` method:
1257+
1258+
.. code-block:: python
1259+
1260+
import pendulum
1261+
1262+
start = pendulum.Pendulum(2000, 1, 1)
1263+
end = pendulum.Pendulum(2000, 1, 10)
1264+
1265+
period = pendulum.period(start, end)
1266+
1267+
for dt in period.range('days'):
1268+
print(dt)
1269+
1270+
'2000-01-01T00:00:00+00:00'
1271+
'2000-01-02T00:00:00+00:00'
1272+
'2000-01-03T00:00:00+00:00'
1273+
'2000-01-04T00:00:00+00:00'
1274+
'2000-01-05T00:00:00+00:00'
1275+
'2000-01-06T00:00:00+00:00'
1276+
'2000-01-07T00:00:00+00:00'
1277+
'2000-01-08T00:00:00+00:00'
1278+
'2000-01-09T00:00:00+00:00'
1279+
'2000-01-10T00:00:00+00:00'
1280+
1281+
.. note::
1282+
1283+
Supported units for ``range()`` are: ``years``, ``months``, ``weeks``,
1284+
``days``, ``hours``, ``minutes`` and ``seconds``
1285+
1286+
.. note::
1287+
1288+
If you just want a generator you can use the ``xrange()`` method.
1289+
1290+
You can also directly iterate over the ``Period`` instance, the unit will be ``days`` in this case:
1291+
1292+
.. code-block:: python
1293+
1294+
for dt in period:
1295+
print(dt)
1296+
1297+
You can check if a ``Pendulum`` instance is inside a period using the ``in`` keyword:
1298+
1299+
.. code-block:: python
1300+
1301+
dt = Pendulum(2000, 1, 4)
1302+
1303+
dt in period
1304+
True

pendulum/period.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3+
import operator
34
from .mixins.interval import WordableIntervalMixin
45
from .interval import BaseInterval
56

@@ -86,4 +87,29 @@ def in_weekend_days(self):
8687

8788
return days * (-1 if not self._absolute and self.invert else 1)
8889

90+
def range(self, unit):
91+
return list(self.xrange(unit))
8992

93+
def xrange(self, unit):
94+
method = 'add'
95+
op = operator.le
96+
if not self._absolute and self.invert:
97+
method = 'subtract'
98+
op = operator.ge
99+
100+
start, end = self.start, self.end
101+
while op(start, end):
102+
yield start
103+
104+
start = getattr(start, method)(**{unit: 1})
105+
106+
def __iter__(self):
107+
return self.xrange('days')
108+
109+
def __contains__(self, item):
110+
from .pendulum import Pendulum
111+
112+
if not isinstance(item, Pendulum):
113+
item = Pendulum.instance(item)
114+
115+
return item.between(self.start, self.end)

tests/period_tests/test_range.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from datetime import datetime
4+
from pendulum import Period, Pendulum
5+
6+
from .. import AbstractTestCase
7+
8+
9+
class RangeTest(AbstractTestCase):
10+
11+
def test_range(self):
12+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
13+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
14+
15+
p = Period(dt1, dt2)
16+
r = p.range('days')
17+
self.assertEqual(31, len(r))
18+
self.assertPendulum(r[0], 2000, 1, 1, 12, 45, 37)
19+
self.assertPendulum(r[-1], 2000, 1, 31, 12, 45, 37)
20+
21+
def test_range_no_overflow(self):
22+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
23+
dt2 = Pendulum(2000, 1, 31, 11, 45, 37)
24+
25+
p = Period(dt1, dt2)
26+
r = p.range('days')
27+
self.assertEqual(30, len(r))
28+
self.assertPendulum(r[0], 2000, 1, 1, 12, 45, 37)
29+
self.assertPendulum(r[-1], 2000, 1, 30, 12, 45, 37)
30+
31+
def test_range_inverted(self):
32+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
33+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
34+
35+
p = Period(dt2, dt1)
36+
r = p.range('days')
37+
self.assertEqual(31, len(r))
38+
self.assertPendulum(r[-1], 2000, 1, 1, 12, 45, 37)
39+
self.assertPendulum(r[0], 2000, 1, 31, 12, 45, 37)
40+
41+
def test_iter(self):
42+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
43+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
44+
45+
p = Period(dt1, dt2)
46+
i = 0
47+
for dt in p:
48+
self.assertIsInstanceOfPendulum(dt)
49+
i += 1
50+
51+
self.assertEqual(31, i)
52+
53+
def test_contains(self):
54+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
55+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
56+
57+
p = Period(dt1, dt2)
58+
dt = Pendulum(2000, 1, 7)
59+
self.assertTrue(dt in p)
60+
61+
def test_not_contains(self):
62+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
63+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
64+
65+
p = Period(dt1, dt2)
66+
dt = Pendulum(2000, 1, 1, 11, 45, 37)
67+
self.assertFalse(dt in p)
68+
69+
def test_contains_with_datetime(self):
70+
dt1 = Pendulum(2000, 1, 1, 12, 45, 37)
71+
dt2 = Pendulum(2000, 1, 31, 12, 45, 37)
72+
73+
p = Period(dt1, dt2)
74+
dt = datetime(2000, 1, 7)
75+
self.assertTrue(dt in p)

0 commit comments

Comments
 (0)