Skip to content

Follow-up to #17419 #17497

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 3 commits into from
Sep 12, 2017
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
5 changes: 2 additions & 3 deletions pandas/_libs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
7 changes: 4 additions & 3 deletions pandas/_libs/src/inference.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion pandas/_libs/tslib.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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)
66 changes: 7 additions & 59 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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."""
Expand Down
8 changes: 8 additions & 0 deletions pandas/_libs/tslibs/timezones.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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)
68 changes: 67 additions & 1 deletion pandas/_libs/tslibs/timezones.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,77 @@
# 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


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)