Skip to content

Instantly share code, notes, and snippets.

@anatoly-scherbakov
Created April 5, 2020 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anatoly-scherbakov/593770d446a06f109438a134863ba969 to your computer and use it in GitHub Desktop.
Save anatoly-scherbakov/593770d446a06f109438a134863ba969 to your computer and use it in GitHub Desktop.
Months range
import itertools
import functools
from typing import Iterator
import datetime
from dateutil.relativedelta import relativedelta
def month_range(
start: datetime.date,
end: datetime.date,
) -> Iterator[datetime.date]:
"""Yields the 1st day of each month in the given date range."""
yield from itertools.takewhile(
lambda date: date < end,
itertools.accumulate(
itertools.repeat(relativedelta(months=1)),
operator.add,
initial=start,
)
)
if __name__ == '__main__':
print(list(month_range(
datetime.date(2017, 1, 1),
datetime.date(2018, 3, 4),
)))
# [
# datetime.date(2017, 1, 1), datetime.date(2017, 2, 1), datetime.date(2017, 3, 1), datetime.date(2017, 4, 1),
# datetime.date(2017, 5, 1), datetime.date(2017, 6, 1), datetime.date(2017, 7, 1), datetime.date(2017, 8, 1),
# datetime.date(2017, 9, 1), datetime.date(2017, 10, 1), datetime.date(2017, 11, 1), datetime.date(2017, 12, 1),
# datetime.date(2018, 1, 1), datetime.date(2018, 2, 1), datetime.date(2018, 3, 1)
# ]
@anatoly-scherbakov
Copy link
Author

anatoly-scherbakov commented Apr 5, 2020

I attempted to replace lambda date: date < end with functools.partial(operator.le, b=end) but operator.le does not treat b as a keyword argument. Not sure if that is possible.

P. S. This requires Python 3.8 due to initial= argument for itertools.accumulate().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment