Skip to content

Commit 01053af

Browse files
committed
Add next_anniversary functions to Date and DateTime
1 parent ce4d3aa commit 01053af

File tree

5 files changed

+49
-36
lines changed

5 files changed

+49
-36
lines changed

docs/docs/comparison.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,16 @@ the `now()` is created in the same timezone as the instance.
6767
>>> birthday = pendulum.datetime(2014, 2, 23)
6868
>>> past_birthday = pendulum.now().subtract(years=50)
6969

70-
>>> born.is_birthday(not_birthday)
70+
>>> born.is_anniversary(not_birthday)
7171
False
72-
>>> born.is_birthday(birthday)
72+
>>> born.is_anniversary(birthday)
7373
True
74-
>>> past_birthday.is_birthday()
74+
>>> past_birthday.is_anniversary()
7575
# Compares to now by default
7676
True
77+
>>> born.next_anniversary()
78+
# Compares to now by default
79+
DateTime(2021, 4, 23, 0, 0, 0, tzinfo=Timezone('UTC'))
80+
>>> born.next_anniversary(not_birthday)
81+
DateTime(2015, 4, 23, 0, 0, 0, tzinfo=Timezone('UTC'))
7782
```

pendulum/date.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,17 @@ def is_anniversary(self, dt=None):
212212

213213
return (self.month, self.day) == (instance.month, instance.day)
214214

215-
# the additional method for checking if today is the anniversary day
216-
# the alias is provided to start using a new name and keep the backward compatibility
217-
# the old name can be completely replaced with the new in one of the future versions
218-
is_birthday = is_anniversary
215+
def next_anniversary(self, dt=None) -> "Date":
216+
"""
217+
Return the next anniversary date, either from today, or the given date
218+
"""
219+
if dt is None:
220+
dt = Date.today()
221+
222+
years = dt.year - self.year
223+
this_year = self.add(years=years)
224+
225+
return this_year if this_year.is_future() else self.add(years=years + 1)
219226

220227
# ADDITIONS AND SUBSTRACTIONS
221228

pendulum/datetime.py

+12
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,18 @@ def is_anniversary(self, dt: Optional[datetime.datetime] = None) -> bool:
451451

452452
return (self.month, self.day) == (instance.month, instance.day)
453453

454+
def next_anniversary(self, dt=None) -> "DateTime":
455+
"""
456+
Return the next anniversary datetime, either from today, or the given datetime
457+
"""
458+
if dt is None:
459+
dt = self.now(self.tz)
460+
461+
years = dt.year - self.year
462+
this_year = self.add(years=years)
463+
464+
return this_year if this_year.is_future() else self.add(years=years + 1)
465+
454466
# ADDITIONS AND SUBSTRACTIONS
455467

456468
def add(

tests/date/test_comparison.py

+9-14
Original file line numberDiff line numberDiff line change
@@ -153,20 +153,15 @@ def test_is_anniversary():
153153
assert d3.is_anniversary(d1)
154154

155155

156-
def test_is_birthday(): # backward compatibility
157-
d = pendulum.Date.today()
158-
an_anniversary = d.subtract(years=1)
159-
assert an_anniversary.is_birthday()
160-
not_an_anniversary = d.subtract(days=1)
161-
assert not not_an_anniversary.is_birthday()
162-
also_not_an_anniversary = d.add(days=2)
163-
assert not also_not_an_anniversary.is_birthday()
164-
165-
d1 = pendulum.Date(1987, 4, 23)
166-
d2 = pendulum.Date(2014, 9, 26)
167-
d3 = pendulum.Date(2014, 4, 23)
168-
assert not d2.is_birthday(d1)
169-
assert d3.is_birthday(d1)
156+
def test_next_anniversary():
157+
start = pendulum.Date(1987, 6, 23)
158+
leap_start = pendulum.Date(1988, 2, 29)
159+
160+
assert start.next_anniversary() == pendulum.Date(2020, 6, 23)
161+
assert leap_start.next_anniversary() == pendulum.Date(2021, 2, 28)
162+
next_year = pendulum.Date(2021, 1, 1)
163+
assert start.next_anniversary(dt=next_year) == pendulum.Date(2021, 6, 23)
164+
assert leap_start.next_anniversary(dt=next_year) == pendulum.Date(2021, 2, 28)
170165

171166

172167
def test_closest():

tests/datetime/test_comparison.py

+9-15
Original file line numberDiff line numberDiff line change
@@ -254,21 +254,15 @@ def test_is_anniversary():
254254
assert d3.is_anniversary(d1)
255255

256256

257-
def test_is_birthday(): # backward compatibility
258-
with pendulum.test(pendulum.now()):
259-
d = pendulum.now()
260-
an_anniversary = d.subtract(years=1)
261-
assert an_anniversary.is_birthday()
262-
not_an_anniversary = d.subtract(days=1)
263-
assert not not_an_anniversary.is_birthday()
264-
also_not_an_anniversary = d.add(days=2)
265-
assert not also_not_an_anniversary.is_birthday()
266-
267-
d1 = pendulum.datetime(1987, 4, 23)
268-
d2 = pendulum.datetime(2014, 9, 26)
269-
d3 = pendulum.datetime(2014, 4, 23)
270-
assert not d2.is_birthday(d1)
271-
assert d3.is_birthday(d1)
257+
def test_next_anniversary():
258+
start = pendulum.datetime(1987, 6, 23)
259+
leap_start = pendulum.datetime(1988, 2, 29)
260+
261+
assert start.next_anniversary() == pendulum.datetime(2020, 6, 23)
262+
assert leap_start.next_anniversary() == pendulum.datetime(2021, 2, 28)
263+
next_year = pendulum.datetime(2021, 1, 1)
264+
assert start.next_anniversary(dt=next_year) == pendulum.datetime(2021, 6, 23)
265+
assert leap_start.next_anniversary(dt=next_year) == pendulum.datetime(2021, 2, 28)
272266

273267

274268
def test_closest():

0 commit comments

Comments
 (0)