特定の期間が与えられた際に、月毎にグループ分けを行いたい


pythonで特定の期間（start, end）が与えられた際に、月毎にグループ分けを行いたいです。  
具体的には、1/15 - 3/3という期間が与えられた場合には、  
1/15 - 1/31, 2/1 - 2/28, 3/1 - 3/3という形でグループ分けしたいです。

とりあえず下記のコードで実現はできましたが、下記の2点から良い方法、シンプルな方法があるのではないかと考えております。

  1. グループ分けを行える関数がありそう（itertools.groupbyをうまくつかう？）
  2. 前月の最終日を求める所が冗長

改善点等ありましたら教えてください。

[code]

    from datetime import datetime, timedelta, date
    from dateutil.relativedelta import relativedelta
    def hoge(start, end):
        def _hoge(l, s, e):
            one_month_after = s + relativedelta(months=1)
            next_month = date(one_month_after.year, one_month_after.month, 1)
            month_last_day = next_month - timedelta(days=1)
            if e <= month_last_day:
                l.append((s, e))
                return l
            l.append((s, month_last_day))
            return _hoge(l, next_month, e)
        return _hoge([], start, end)
    
    hoge(date(2019, 1, 15), date(2019, 3, 3))
    
[/code]

出力

[code]

    # [(datetime.date(2019, 1, 15), datetime.date(2019, 1, 31)),
    #  (datetime.date(2019, 2, 1), datetime.date(2019, 2, 28)),
    #  (datetime.date(2019, 3, 1), datetime.date(2019, 3, 3))]
    
[/code]




`itertools.groupby()` を使うとすれば以下の様になります。

[code]

    from datetime import date, timedelta
    from itertools import groupby
    
    def hoge(start, end):
      return [(d[0], d[-1]) for d in [list(v) for _, v in groupby(
        [start + timedelta(days=x) for x in range(0, (end-start).days+1)],
        key = lambda x: (x.year, x.month))]]
    
    hoge(date(2019, 1, 15), date(2019, 3, 3))
    
[/code]

pandas を使うと簡潔になるかもしれません。

ところで、

[code]

    hoge(date(2019, 1, 31), date(2019, 3, 1))
    
[/code]

とすると、結果は以下の様になるのですが、これはこれでよろしいのでしょうか？

[code]

    [(datetime.date(2019, 1, 31), datetime.date(2019, 1, 31)),
     (datetime.date(2019, 2, 1), datetime.date(2019, 2, 28)),
     (datetime.date(2019, 3, 1), datetime.date(2019, 3, 1))]
    
[/code]




`itertools.groupby()` を使うとすれば以下の様になります。

[code]

    from datetime import date, timedelta
    from itertools import groupby
    
    def hoge(start, end):
      return [(d[0], d[-1]) for d in [list(v) for _, v in groupby(
        [start + timedelta(days=x) for x in range(0, (end-start).days+1)],
        key = lambda x: (x.year, x.month))]]
    
    hoge(date(2019, 1, 15), date(2019, 3, 3))
    
[/code]

pandas を使うと簡潔になるかもしれません。

ところで、

[code]

    hoge(date(2019, 1, 31), date(2019, 3, 1))
    
[/code]

とすると、結果は以下の様になるのですが、これはこれでよろしいのでしょうか？

[code]

    [(datetime.date(2019, 1, 31), datetime.date(2019, 1, 31)),
     (datetime.date(2019, 2, 1), datetime.date(2019, 2, 28)),
     (datetime.date(2019, 3, 1), datetime.date(2019, 3, 1))]
    
[/code]

