Skip to content

PERF: Use ccalendar.get_days_in_month over tslib.monthrange #21451

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

Merged
merged 1 commit into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ from tslibs.np_datetime cimport (check_dts_bounds,
_string_to_dts,
dt64_to_dtstruct, dtstruct_to_dt64,
pydatetime_to_dt64, pydate_to_dt64,
get_datetime64_value,
days_per_month_table,
dayofweek, is_leapyear)
get_datetime64_value)
from tslibs.np_datetime import OutOfBoundsDatetime

from tslibs.parsing import parse_datetime_string
Expand Down Expand Up @@ -763,18 +761,6 @@ cdef inline bint _parse_today_now(str val, int64_t* iresult):
# Some general helper functions


def monthrange(int64_t year, int64_t month):
cdef:
int64_t days

if month < 1 or month > 12:
raise ValueError("bad month number 0; must be 1-12")

days = days_per_month_table[is_leapyear(year)][month - 1]

return (dayofweek(year, month, 1), days)


cpdef normalize_date(object dt):
"""
Normalize datetime.datetime value to midnight. Returns datetime.date as a
Expand Down
4 changes: 2 additions & 2 deletions pandas/_libs/tslibs/resolution.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ from fields import build_field_sarray
from conversion import tz_convert
from conversion cimport tz_convert_utc_to_tzlocal
from ccalendar import MONTH_ALIASES, int_to_weekday
from ccalendar cimport get_days_in_month

from pandas._libs.properties import cache_readonly
from pandas._libs.tslib import Timestamp
Expand Down Expand Up @@ -487,7 +488,6 @@ class _FrequencyInferer(object):
days = self.fields['D']
weekdays = self.index.dayofweek

from calendar import monthrange
for y, m, d, wd in zip(years, months, days, weekdays):

if calendar_start:
Expand All @@ -496,7 +496,7 @@ class _FrequencyInferer(object):
business_start &= d == 1 or (d <= 3 and wd == 0)

if calendar_end or business_end:
_, daysinmonth = monthrange(y, m)
daysinmonth = get_days_in_month(y, m)
cal = d == daysinmonth
if calendar_end:
calendar_end &= cal
Expand Down
5 changes: 3 additions & 2 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from pandas._libs import (lib, index as libindex, tslib as libts,
join as libjoin, Timestamp)
from pandas._libs.tslibs import (timezones, conversion, fields, parsing,
ccalendar,
resolution as libresolution)

# -------- some conversion wrapper functions
Expand Down Expand Up @@ -1451,14 +1452,14 @@ def _parsed_string_to_bounds(self, reso, parsed):
Timestamp(datetime(parsed.year, 12, 31, 23,
59, 59, 999999), tz=self.tz))
elif reso == 'month':
d = libts.monthrange(parsed.year, parsed.month)[1]
d = ccalendar.get_days_in_month(parsed.year, parsed.month)
return (Timestamp(datetime(parsed.year, parsed.month, 1),
tz=self.tz),
Timestamp(datetime(parsed.year, parsed.month, d, 23,
59, 59, 999999), tz=self.tz))
elif reso == 'quarter':
qe = (((parsed.month - 1) + 2) % 12) + 1 # two months ahead
d = libts.monthrange(parsed.year, qe)[1] # at end of month
d = ccalendar.get_days_in_month(parsed.year, qe) # at end of month
return (Timestamp(datetime(parsed.year, parsed.month, 1),
tz=self.tz),
Timestamp(datetime(parsed.year, qe, d, 23, 59,
Expand Down
6 changes: 0 additions & 6 deletions pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@
from .common import assert_offset_equal, assert_onOffset


def test_monthrange():
import calendar
for y in range(2000, 2013):
for m in range(1, 13):
assert tslib.monthrange(y, m) == calendar.monthrange(y, m)

####
# Misc function tests
####
Expand Down
4 changes: 2 additions & 2 deletions pandas/tseries/offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ def apply(self, other):
# shift `other` to self.day_of_month, incrementing `n` if necessary
n = liboffsets.roll_convention(other.day, self.n, self.day_of_month)

days_in_month = tslib.monthrange(other.year, other.month)[1]
days_in_month = ccalendar.get_days_in_month(other.year, other.month)

# For SemiMonthBegin on other.day == 1 and
# SemiMonthEnd on other.day == days_in_month,
Expand Down Expand Up @@ -1217,7 +1217,7 @@ class SemiMonthEnd(SemiMonthOffset):
def onOffset(self, dt):
if self.normalize and not _is_normalized(dt):
return False
_, days_in_month = tslib.monthrange(dt.year, dt.month)
days_in_month = ccalendar.get_days_in_month(dt.year, dt.month)
return dt.day in (self.day_of_month, days_in_month)

def _apply(self, n, other):
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ def pxd(name):
'pyxfile': '_libs/tslibs/resolution',
'pxdfiles': ['_libs/src/util',
'_libs/khash',
'_libs/tslibs/ccalendar',
'_libs/tslibs/frequencies',
'_libs/tslibs/timezones'],
'depends': tseries_depends,
Expand Down