Skip to content

Commit

Permalink
Add first_day and last_day (#14)
Browse files Browse the repository at this point in the history
* Add first_day and last_day

* Version bump

* Fix build
  • Loading branch information
raymondjavaxx committed Mar 15, 2024
1 parent d41d427 commit 99e1b55
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -3,6 +3,11 @@ Changelog

All notable changes to this project will be documented in this file.

v0.5.0
------

- Added ``YearMonth.first_day`` and ``YearMonth.last_day`` properties to get the first and last day of the month.

v0.4.0
------

Expand Down
15 changes: 11 additions & 4 deletions mp_yearmonth/yearmonth.py
Expand Up @@ -138,6 +138,16 @@ def numdays(self) -> int:
_, days = calendar.monthrange(self.year, self.month)
return days

@property
def first_day(self) -> datetime.date:
"""Return the first day of the month."""
return datetime.date(self.year, self.month, 1)

@property
def last_day(self) -> datetime.date:
"""Return the last day of the month."""
return datetime.date(self.year, self.month, self.numdays)

@classmethod
def current(cls, tz: Optional[datetime.tzinfo] = None) -> "YearMonth":
"""Return the current year and month.
Expand Down Expand Up @@ -172,10 +182,7 @@ def prev(self) -> "YearMonth":

def bounds(self) -> Tuple[datetime.date, datetime.date]:
"""Return the first and last day of the month."""
return (
datetime.date(self.year, self.month, 1),
datetime.date(self.year, self.month, self.numdays),
)
return (self.first_day, self.last_day)

def applying_delta(self, months: int) -> "YearMonth":
"""Return the YearMonth that is `months` away from this one."""
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mp-yearmonth"
version = "0.4.0"
version = "0.5.0"
description = "A year-month datatype for Python."
keywords = ["year", "month", "date", "calendar"]
authors = ["Ramon Torres <ramon@macropoetry.com>"]
Expand Down
40 changes: 34 additions & 6 deletions tests/test_yearmonth.py
@@ -1,5 +1,6 @@
import pytest
import datetime
from typing import Tuple
from freezegun import freeze_time
from mp_yearmonth import YearMonth

Expand Down Expand Up @@ -103,6 +104,26 @@ def test_numdays():
assert YearMonth(2020, 2).numdays == 29


def test_first_day():
ym1 = YearMonth(2021, 1)
assert ym1.first_day == datetime.date(2021, 1, 1)

ym2 = YearMonth(2021, 2)
assert ym2.first_day == datetime.date(2021, 2, 1)


@pytest.mark.parametrize(
("year_month", "expected_last_day"),
[
(YearMonth(2021, 1), datetime.date(2021, 1, 31)),
(YearMonth(2021, 2), datetime.date(2021, 2, 28)),
(YearMonth(2020, 2), datetime.date(2020, 2, 29)), # Leap year
],
)
def test_last_day(year_month: YearMonth, expected_last_day: datetime.date):
assert year_month.last_day == expected_last_day


@freeze_time("2021-01-01") # UTC
def test_current():
assert YearMonth.current() == YearMonth(2021, 1)
Expand Down Expand Up @@ -225,9 +246,16 @@ def test_contains_handles_unsupported_types():
assert "test" not in YearMonth(2021, 1)


def test_bounds():
ym1 = YearMonth(2021, 1)
assert ym1.bounds() == (datetime.date(2021, 1, 1), datetime.date(2021, 1, 31))

ym2 = YearMonth(2021, 2)
assert ym2.bounds() == (datetime.date(2021, 2, 1), datetime.date(2021, 2, 28))
@pytest.mark.parametrize(
("year_month", "expected"),
[
(YearMonth(2021, 1), (datetime.date(2021, 1, 1), datetime.date(2021, 1, 31))),
(YearMonth(2021, 2), (datetime.date(2021, 2, 1), datetime.date(2021, 2, 28))),
(
YearMonth(2020, 2),
(datetime.date(2020, 2, 1), datetime.date(2020, 2, 29)),
), # Leap year
],
)
def test_bounds(year_month: YearMonth, expected: Tuple[datetime.date, datetime.date]):
assert year_month.bounds() == expected

0 comments on commit 99e1b55

Please sign in to comment.