diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 0f58cfa761f21..4f73f196b0d9d 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -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 @@ -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 diff --git a/pandas/_libs/tslibs/resolution.pyx b/pandas/_libs/tslibs/resolution.pyx index d0a9501afe566..2f185f4142a09 100644 --- a/pandas/_libs/tslibs/resolution.pyx +++ b/pandas/_libs/tslibs/resolution.pyx @@ -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 @@ -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: @@ -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 diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index d44b13172f86d..66622814f172d 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -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 @@ -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, diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py index 5369b1a94a956..a1c5a825054ec 100644 --- a/pandas/tests/tseries/offsets/test_offsets.py +++ b/pandas/tests/tseries/offsets/test_offsets.py @@ -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 #### diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index c294110d89ec5..a5a983bf94bb8 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -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, @@ -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): diff --git a/setup.py b/setup.py index 90ec8e91a0700..d6890a08b09d0 100755 --- a/setup.py +++ b/setup.py @@ -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,