New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WeekOfMonth vs LastWeekOfMonth inconsistency #18672

Closed
jbrockmendel opened this Issue Dec 6, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@jbrockmendel
Member

jbrockmendel commented Dec 6, 2017

https://github.com/pandas-dev/pandas/blob/master/pandas/tseries/offsets.py#L1496

WeekOfMonth and LastWeekOfMonth have small differences in how they construct getOffsetOfMonth and then in what they do with it. It looks fishy. Any idea why these are done differently? If there's not a reason for it, I'd like to align+merge them.

class WeekOfMonth(DateOffset):
    [...]
    @apply_wraps
    def apply(self, other):
        base = other
        offsetOfMonth = self.getOffsetOfMonth(other)

        months = self.n
        if months > 0 and offsetOfMonth > other:
            months -= 1
        elif months <= 0 and offsetOfMonth < other:
            months += 1

        other = self.getOffsetOfMonth(shift_month(other, months, 'start'))
        other = datetime(other.year, other.month, other.day, base.hour,
                         base.minute, base.second, base.microsecond)
        return other

    def getOffsetOfMonth(self, dt):
        w = Week(weekday=self.weekday)
        d = datetime(dt.year, dt.month, 1, tzinfo=dt.tzinfo)
        # TODO: Is this DST-safe?
        d = w.rollforward(d)
        return d + timedelta(weeks=self.week)


    def onOffset(self, dt):
        if self.normalize and not _is_normalized(dt):
            return False
        d = datetime(dt.year, dt.month, dt.day, tzinfo=dt.tzinfo)
        return d == self.getOffsetOfMonth(dt)

class LastWeekOfMonth(DateOffset):
    [...]
    @apply_wraps
    def apply(self, other):
        offsetOfMonth = self.getOffsetOfMonth(other)

        months = self.n
        if months > 0 and offsetOfMonth > other:
            months -= 1
        elif months <= 0 and offsetOfMonth < other:
            months += 1

        return self.getOffsetOfMonth(shift_month(other, months, 'start'))

    def getOffsetOfMonth(self, dt):
        m = MonthEnd()
        d = datetime(dt.year, dt.month, 1, dt.hour, dt.minute,
                     dt.second, dt.microsecond, tzinfo=dt.tzinfo)
        eom = m.rollforward(d)
        # TODO: Is this DST-safe?
        w = Week(weekday=self.weekday)
        return w.rollback(eom)

    def onOffset(self, dt):
        if self.normalize and not _is_normalized(dt):
            return False
        return dt == self.getOffsetOfMonth(dt)

@jbrockmendel

This comment has been minimized.

Member

jbrockmendel commented Dec 6, 2017

TL;DR look at WeekOfMonth.getOffsetOfMonth. Why would we drop hour minute second but keep tzinfo?

@jbrockmendel

This comment has been minimized.

Member

jbrockmendel commented Dec 19, 2017

@gfyoung There are a whole bunch of (offset+timezone)-related issues that I need input on before I can fix (many of them found when running tests with hypothesis). Is there someone I can ask about these other than jreback? I bug him enough as it is.

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