diff --git a/pandas/_libs/period.pyx b/pandas/_libs/period.pyx index 08962bca824ca..2b0734f5cf2e7 100644 --- a/pandas/_libs/period.pyx +++ b/pandas/_libs/period.pyx @@ -33,11 +33,10 @@ from util cimport is_period_object, is_string_object from lib cimport is_null_datetimelike, is_period from pandas._libs import tslib, lib from pandas._libs.tslib import (Timedelta, Timestamp, iNaT, - NaT, _get_utcoffset) -from tslibs.timezones cimport _is_utc + NaT) +from tslibs.timezones cimport _is_utc, _is_tzlocal, _get_utcoffset from tslib cimport ( maybe_get_tz, - _is_tzlocal, _get_dst_info, _nat_scalar_rules) diff --git a/pandas/_libs/src/inference.pyx b/pandas/_libs/src/inference.pyx index 6b5a8f20f0067..95145ff49b02f 100644 --- a/pandas/_libs/src/inference.pyx +++ b/pandas/_libs/src/inference.pyx @@ -2,7 +2,8 @@ import sys from decimal import Decimal cimport util cimport cython -from tslib import NaT, get_timezone +from tslib import NaT +from tslibs.timezones cimport _get_zone from datetime import datetime, timedelta iNaT = util.get_nat() @@ -900,13 +901,13 @@ cpdef bint is_datetime_with_singletz_array(ndarray[object] values): for i in range(n): base_val = values[i] if base_val is not NaT: - base_tz = get_timezone(getattr(base_val, 'tzinfo', None)) + base_tz = _get_zone(getattr(base_val, 'tzinfo', None)) for j in range(i, n): val = values[j] if val is not NaT: tz = getattr(val, 'tzinfo', None) - if base_tz != tz and base_tz != get_timezone(tz): + if base_tz != tz and base_tz != _get_zone(tz): return False break diff --git a/pandas/_libs/tslib.pxd b/pandas/_libs/tslib.pxd index 1d81c3cc15cd8..c1b25963a6257 100644 --- a/pandas/_libs/tslib.pxd +++ b/pandas/_libs/tslib.pxd @@ -3,7 +3,6 @@ from numpy cimport ndarray, int64_t cdef convert_to_tsobject(object, object, object, bint, bint) cpdef convert_to_timedelta64(object, object) cpdef object maybe_get_tz(object) -cdef bint _is_tzlocal(object) cdef object _get_dst_info(object) cdef bint _nat_scalar_rules[6] cdef bint _check_all_nulls(obj) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index b1f794a0030d1..a8ae0fcd733d6 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -107,7 +107,13 @@ cdef int64_t NPY_NAT = util.get_nat() iNaT = NPY_NAT -from tslibs.timezones cimport _is_utc +from tslibs.timezones cimport ( + _is_utc, _is_tzlocal, + _treat_tz_as_dateutil, _treat_tz_as_pytz, + _get_zone, + _get_utcoffset) +from tslibs.timezones import get_timezone, _get_utcoffset # noqa + cdef inline object create_timestamp_from_ts( int64_t value, pandas_datetimestruct dts, @@ -235,10 +241,6 @@ def ints_to_pytimedelta(ndarray[int64_t] arr, box=False): return result -cdef inline bint _is_tzlocal(object tz): - return isinstance(tz, _dateutil_tzlocal) - - cdef inline bint _is_fixed_offset(object tz): if _treat_tz_as_dateutil(tz): if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0: @@ -1443,11 +1445,6 @@ cdef class _TSObject: def __get__(self): return self.value -cpdef _get_utcoffset(tzinfo, obj): - try: - return tzinfo._utcoffset - except AttributeError: - return tzinfo.utcoffset(obj) # helper to extract datetime and int64 from several different possibilities cdef convert_to_tsobject(object ts, object tz, object unit, @@ -1712,48 +1709,6 @@ def _localize_pydatetime(object dt, object tz): return dt.replace(tzinfo=tz) -def get_timezone(tz): - return _get_zone(tz) - - -cdef inline object _get_zone(object tz): - """ - We need to do several things here: - 1) Distinguish between pytz and dateutil timezones - 2) Not be over-specific (e.g. US/Eastern with/without DST is same *zone* - but a different tz object) - 3) Provide something to serialize when we're storing a datetime object - in pytables. - - We return a string prefaced with dateutil if it's a dateutil tz, else just - the tz name. It needs to be a string so that we can serialize it with - UJSON/pytables. maybe_get_tz (below) is the inverse of this process. - """ - if _is_utc(tz): - return 'UTC' - else: - if _treat_tz_as_dateutil(tz): - if '.tar.gz' in tz._filename: - raise ValueError( - 'Bad tz filename. Dateutil on python 3 on windows has a ' - 'bug which causes tzfile._filename to be the same for all ' - 'timezone files. Please construct dateutil timezones ' - 'implicitly by passing a string like "dateutil/Europe' - '/London" when you construct your pandas objects instead ' - 'of passing a timezone object. See ' - 'https://github.com/pandas-dev/pandas/pull/7362') - return 'dateutil/' + tz._filename - else: - # tz is a pytz timezone or unknown. - try: - zone = tz.zone - if zone is None: - return tz - return zone - except AttributeError: - return tz - - cpdef inline object maybe_get_tz(object tz): """ (Maybe) Construct a timezone object from a string. If tz is a string, use @@ -4285,13 +4240,6 @@ def tz_convert_single(int64_t val, object tz1, object tz2): # Timezone data caches, key is the pytz string or dateutil file name. dst_cache = {} -cdef inline bint _treat_tz_as_pytz(object tz): - return hasattr(tz, '_utc_transition_times') and hasattr( - tz, '_transition_info') - -cdef inline bint _treat_tz_as_dateutil(object tz): - return hasattr(tz, '_trans_list') and hasattr(tz, '_trans_idx') - def _p_tz_cache_key(tz): """ Python interface for cache function to facilitate testing.""" diff --git a/pandas/_libs/tslibs/timezones.pxd b/pandas/_libs/tslibs/timezones.pxd index 0708282abe1d0..897bd8af7e2de 100644 --- a/pandas/_libs/tslibs/timezones.pxd +++ b/pandas/_libs/tslibs/timezones.pxd @@ -2,3 +2,11 @@ # cython: profile=False cdef bint _is_utc(object tz) +cdef bint _is_tzlocal(object tz) + +cdef bint _treat_tz_as_pytz(object tz) +cdef bint _treat_tz_as_dateutil(object tz) + +cdef object _get_zone(object tz) + +cpdef _get_utcoffset(tzinfo, obj) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 43709e77b70d5..249eedef4bb09 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -2,7 +2,9 @@ # cython: profile=False # dateutil compat -from dateutil.tz import tzutc as _dateutil_tzutc +from dateutil.tz import ( + tzutc as _dateutil_tzutc, + tzlocal as _dateutil_tzlocal) import pytz UTC = pytz.utc @@ -10,3 +12,67 @@ UTC = pytz.utc cdef inline bint _is_utc(object tz): return tz is UTC or isinstance(tz, _dateutil_tzutc) + + +cdef inline bint _is_tzlocal(object tz): + return isinstance(tz, _dateutil_tzlocal) + + +cdef inline bint _treat_tz_as_pytz(object tz): + return hasattr(tz, '_utc_transition_times') and hasattr( + tz, '_transition_info') + + +cdef inline bint _treat_tz_as_dateutil(object tz): + return hasattr(tz, '_trans_list') and hasattr(tz, '_trans_idx') + + +cdef inline object _get_zone(object tz): + """ + We need to do several things here: + 1) Distinguish between pytz and dateutil timezones + 2) Not be over-specific (e.g. US/Eastern with/without DST is same *zone* + but a different tz object) + 3) Provide something to serialize when we're storing a datetime object + in pytables. + + We return a string prefaced with dateutil if it's a dateutil tz, else just + the tz name. It needs to be a string so that we can serialize it with + UJSON/pytables. maybe_get_tz (below) is the inverse of this process. + """ + if _is_utc(tz): + return 'UTC' + else: + if _treat_tz_as_dateutil(tz): + if '.tar.gz' in tz._filename: + raise ValueError( + 'Bad tz filename. Dateutil on python 3 on windows has a ' + 'bug which causes tzfile._filename to be the same for all ' + 'timezone files. Please construct dateutil timezones ' + 'implicitly by passing a string like "dateutil/Europe' + '/London" when you construct your pandas objects instead ' + 'of passing a timezone object. See ' + 'https://github.com/pandas-dev/pandas/pull/7362') + return 'dateutil/' + tz._filename + else: + # tz is a pytz timezone or unknown. + try: + zone = tz.zone + if zone is None: + return tz + return zone + except AttributeError: + return tz + + +def get_timezone(tz): + return _get_zone(tz) + +#---------------------------------------------------------------------- +# UTC Offsets + +cpdef _get_utcoffset(tzinfo, obj): + try: + return tzinfo._utcoffset + except AttributeError: + return tzinfo.utcoffset(obj)