Skip to content

QST: Howto write a custom DateOffset  #35569

@MaxWinterstein

Description

@MaxWinterstein

We need multiple custom DateOffset, e.g. so called MonthHalf.
Until Release 1.1.0 we had a working solution:

import pandas as pd

class MonthHalf(pd.offsets.DateOffset):
    """Date offset repeating on the first date of the month and a day in the middle of the month.

    For February the middle day is the 15th, for all other months the 16th."""

    _attributes = frozenset(["n"])
    _prefix = "MH"

    __init__ = pd.offsets.BaseOffset.__init__

    @pandas.tseries.offsets.apply_wraps
    def apply(self, other: dt.datetime):

        month_half_day = self._month_half_day(other.month)

        second_month_half = other.day >= month_half_day

        n = self.n
        new = other

        if n < 0:
            if not self.onOffset(other):
                # Move to the left onto an offset
                if second_month_half:
                    new = new.replace(day=month_half_day)
                else:
                    new = new.replace(day=1)

                # One step already happened
                n += 1

        odd_n = n % 2 == 1

        if n > 0:
            month_difference = n // 2 + second_month_half * odd_n
        elif n == 0:
            month_difference = 0
        else:
            month_difference = n // 2 - second_month_half * (not odd_n)

        if month_difference != 0:
            new = new + month_difference * pd.offsets.MonthBegin()

        month_half_day = self._month_half_day(new.month)

        if odd_n:
            new_day = 1 if second_month_half else month_half_day
        else:
            new_day = month_half_day if second_month_half else 1

        new = new.replace(day=new_day)

        return new

    def onOffset(self, date):
        return date.day in {1, self._month_half_day(date.month)}

    @staticmethod
    def _month_half_day(month: int):
        return 15 if month == 2 else 16

With release 1.1.0 (and i guess the merge of #34062) code is broken.

E.g. The rollback is not working anymore:

def test_rollback():
    date = pd.to_datetime('2018-01-02')
    rollback = MonthHalf().rollback(date)
    assert rollback == dt.date(2018, 1, 1)

How can i implement such need now?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions