Skip to content
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

de-privatize timezone functions #17543

Merged
merged 9 commits into from
Sep 23, 2017
Merged
Show file tree
Hide file tree
Changes from 7 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
6 changes: 3 additions & 3 deletions pandas/_libs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ from pandas._libs import tslib, lib
from pandas._libs.tslib import (Timedelta, Timestamp, iNaT,
NaT)
from tslibs.timezones cimport (
is_utc, is_tzlocal, get_utcoffset, _get_dst_info, maybe_get_tz)
is_utc, is_tzlocal, get_utcoffset, get_dst_info, maybe_get_tz)
from tslib cimport _nat_scalar_rules

from tslibs.frequencies cimport get_freq_code
Expand Down Expand Up @@ -557,7 +557,7 @@ cdef _reso_local(ndarray[int64_t] stamps, object tz):
reso = curr_reso
else:
# Adjust datetime64 timestamp, recompute datetimestruct
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

_pos = trans.searchsorted(stamps, side='right') - 1
if _pos.dtype != np.int64:
Expand Down Expand Up @@ -624,7 +624,7 @@ cdef ndarray[int64_t] localize_dt64arr_to_period(ndarray[int64_t] stamps,
dts.us, dts.ps, freq)
else:
# Adjust datetime64 timestamp, recompute datetimestruct
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

_pos = trans.searchsorted(stamps, side='right') - 1
if _pos.dtype != np.int64:
Expand Down
32 changes: 13 additions & 19 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,10 @@ iNaT = NPY_NAT


from tslibs.timezones cimport (
is_utc, is_tzlocal, _is_fixed_offset,
is_utc, is_tzlocal, is_fixed_offset,
treat_tz_as_dateutil, treat_tz_as_pytz,
get_timezone, get_utcoffset, maybe_get_tz,
_get_dst_info
)
from tslibs.timezones import ( # noqa
get_timezone, get_utcoffset, maybe_get_tz,
_p_tz_cache_key, dst_cache,
_unbox_utcoffsets,
_dateutil_gettz
get_dst_info
)


Expand Down Expand Up @@ -167,7 +161,7 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None, box=False):
pandas_datetime_to_datetimestruct(
value, PANDAS_FR_ns, &dts)
result[i] = func_create(value, dts, tz, freq)
elif is_tzlocal(tz) or _is_fixed_offset(tz):
elif is_tzlocal(tz) or is_fixed_offset(tz):
for i in range(n):
value = arr[i]
if value == NPY_NAT:
Expand All @@ -181,7 +175,7 @@ def ints_to_pydatetime(ndarray[int64_t] arr, tz=None, freq=None, box=False):
dt = Timestamp(dt)
result[i] = dt
else:
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

for i in range(n):

Expand Down Expand Up @@ -1641,12 +1635,12 @@ cdef inline void _localize_tso(_TSObject obj, object tz):
obj.tzinfo = tz
else:
# Adjust datetime64 timestamp, recompute datetimestruct
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

pos = trans.searchsorted(obj.value, side='right') - 1

# static/pytz/dateutil specific code
if _is_fixed_offset(tz):
if is_fixed_offset(tz):
# statictzinfo
if len(deltas) > 0 and obj.value != NPY_NAT:
pandas_datetime_to_datetimestruct(obj.value + deltas[0],
Expand Down Expand Up @@ -4066,7 +4060,7 @@ def tz_convert(ndarray[int64_t] vals, object tz1, object tz2):
* 1000000000)
utc_dates[i] = v - delta
else:
trans, deltas, typ = _get_dst_info(tz1)
trans, deltas, typ = get_dst_info(tz1)

# all-NaT
tt = vals[vals!=NPY_NAT]
Expand Down Expand Up @@ -4108,7 +4102,7 @@ def tz_convert(ndarray[int64_t] vals, object tz1, object tz2):
return result

# Convert UTC to other timezone
trans, deltas, typ = _get_dst_info(tz2)
trans, deltas, typ = get_dst_info(tz2)

# use first non-NaT element
# if all-NaT, return all-NaT
Expand Down Expand Up @@ -4172,7 +4166,7 @@ def tz_convert_single(int64_t val, object tz1, object tz2):
delta = int(get_utcoffset(tz1, dt).total_seconds()) * 1000000000
utc_date = val - delta
elif get_timezone(tz1) != 'UTC':
trans, deltas, typ = _get_dst_info(tz1)
trans, deltas, typ = get_dst_info(tz1)
pos = trans.searchsorted(val, side='right') - 1
if pos < 0:
raise ValueError('First time before start of DST info')
Expand All @@ -4191,7 +4185,7 @@ def tz_convert_single(int64_t val, object tz1, object tz2):
return utc_date + delta

# Convert UTC to other timezone
trans, deltas, typ = _get_dst_info(tz2)
trans, deltas, typ = get_dst_info(tz2)

pos = trans.searchsorted(utc_date, side='right') - 1
if pos < 0:
Expand Down Expand Up @@ -4261,7 +4255,7 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz, object ambiguous=None,
"Length of ambiguous bool-array must be the same size as vals")
ambiguous_array = np.asarray(ambiguous)

trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

tdata = <int64_t*> trans.data
ntrans = len(trans)
Expand Down Expand Up @@ -4967,7 +4961,7 @@ cdef _normalize_local(ndarray[int64_t] stamps, object tz):
result[i] = _normalized_stamp(&dts)
else:
# Adjust datetime64 timestamp, recompute datetimestruct
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

_pos = trans.searchsorted(stamps, side='right') - 1
if _pos.dtype != np.int64:
Expand Down Expand Up @@ -5022,7 +5016,7 @@ def dates_normalized(ndarray[int64_t] stamps, tz=None):
if (dt.hour + dt.minute + dt.second + dt.microsecond) > 0:
return False
else:
trans, deltas, typ = _get_dst_info(tz)
trans, deltas, typ = get_dst_info(tz)

for i in range(n):
# Adjust datetime64 timestamp, recompute datetimestruct
Expand Down
4 changes: 2 additions & 2 deletions pandas/_libs/tslibs/timezones.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ cpdef object get_timezone(object tz)
cpdef object maybe_get_tz(object tz)

cpdef get_utcoffset(tzinfo, obj)
cdef bint _is_fixed_offset(object tz)
cdef bint is_fixed_offset(object tz)

cdef object _get_dst_info(object tz)
cdef object get_dst_info(object tz)
26 changes: 13 additions & 13 deletions pandas/_libs/tslibs/timezones.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ from dateutil.tz import (
import sys
if sys.platform == 'win32' or sys.platform == 'cygwin':
# equiv pd.compat.is_platform_windows()
from dateutil.zoneinfo import gettz as _dateutil_gettz
from dateutil.zoneinfo import gettz as dateutil_gettz
else:
from dateutil.tz import gettz as _dateutil_gettz
from dateutil.tz import gettz as dateutil_gettz


from pytz.tzinfo import BaseTzInfo as _pytz_BaseTzInfo
Expand Down Expand Up @@ -100,7 +100,7 @@ cpdef inline object maybe_get_tz(object tz):
tz = _dateutil_tzlocal()
elif tz.startswith('dateutil/'):
zone = tz[9:]
tz = _dateutil_gettz(zone)
tz = dateutil_gettz(zone)
Copy link
Contributor

@jreback jreback Sep 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so would like to rename these to be more consistent, maybe
get_timezone_from_dateutil

ok with doing it in this PR

# On Python 3 on Windows, the filename is not always set correctly.
if isinstance(tz, _dateutil_tzfile) and '.tar.gz' in tz._filename:
tz._filename = zone
Expand All @@ -113,14 +113,14 @@ cpdef inline object maybe_get_tz(object tz):

def _p_tz_cache_key(tz):
""" Python interface for cache function to facilitate testing."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is dumb that we are exposing a function just to test. I don't think this is actually necessary and should be removed (so maybe leave this one as private).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, best guess is that was created before cpdef was an option. Will re-privatize.

return _tz_cache_key(tz)
return tz_cache_key(tz)


# Timezone data caches, key is the pytz string or dateutil file name.
dst_cache = {}


cdef inline object _tz_cache_key(object tz):
cdef inline object tz_cache_key(object tz):
"""
Return the key in the cache for the timezone info object or None
if unknown.
Expand Down Expand Up @@ -163,7 +163,7 @@ cpdef get_utcoffset(tzinfo, obj):
return tzinfo.utcoffset(obj)


cdef inline bint _is_fixed_offset(object tz):
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:
return 1
Expand All @@ -178,7 +178,7 @@ cdef inline bint _is_fixed_offset(object tz):
return 1


cdef object _get_utc_trans_times_from_dateutil_tz(object tz):
cdef object get_utc_trans_times_from_dateutil_tz(object tz):
"""
Transition times in dateutil timezones are stored in local non-dst
time. This code converts them to UTC. It's the reverse of the code
Expand All @@ -193,7 +193,7 @@ cdef object _get_utc_trans_times_from_dateutil_tz(object tz):
return new_trans


cpdef ndarray _unbox_utcoffsets(object transinfo):
cpdef ndarray unbox_utcoffsets(object transinfo):
cdef:
Py_ssize_t i, sz
ndarray[int64_t] arr
Expand All @@ -211,15 +211,15 @@ cpdef ndarray _unbox_utcoffsets(object transinfo):
# Daylight Savings


cdef object _get_dst_info(object tz):
cdef object get_dst_info(object tz):
"""
return a tuple of :
(UTC times of DST transitions,
UTC offsets in microseconds corresponding to DST transitions,
string of type of transitions)

"""
cache_key = _tz_cache_key(tz)
cache_key = tz_cache_key(tz)
if cache_key is None:
num = int(get_utcoffset(tz, None).total_seconds()) * 1000000000
return (np.array([NPY_NAT + 1], dtype=np.int64),
Expand All @@ -235,13 +235,13 @@ cdef object _get_dst_info(object tz):
trans[0] = NPY_NAT + 1
except Exception:
pass
deltas = _unbox_utcoffsets(tz._transition_info)
deltas = unbox_utcoffsets(tz._transition_info)
typ = 'pytz'

elif treat_tz_as_dateutil(tz):
if len(tz._trans_list):
# get utc trans times
trans_list = _get_utc_trans_times_from_dateutil_tz(tz)
trans_list = get_utc_trans_times_from_dateutil_tz(tz)
trans = np.hstack([
np.array([0], dtype='M8[s]'), # place holder for first item
np.array(trans_list, dtype='M8[s]')]).astype(
Expand All @@ -255,7 +255,7 @@ cdef object _get_dst_info(object tz):
deltas *= 1000000000
typ = 'dateutil'

elif _is_fixed_offset(tz):
elif is_fixed_offset(tz):
trans = np.array([NPY_NAT + 1], dtype=np.int64)
deltas = np.array([tz._ttinfo_std.offset],
dtype='i8') * 1000000000
Expand Down
20 changes: 11 additions & 9 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from pandas._libs import (lib, index as libindex, tslib as libts,
algos as libalgos, join as libjoin,
Timestamp, period as libperiod)
from pandas._libs.tslibs import timezones


def _utc():
Expand Down Expand Up @@ -372,7 +373,7 @@ def __new__(cls, data=None,
tz = subarr.tz
else:
if tz is not None:
tz = libts.maybe_get_tz(tz)
tz = timezones.maybe_get_tz(tz)

if (not isinstance(data, DatetimeIndex) or
getattr(data, 'tz', None) is None):
Expand Down Expand Up @@ -447,17 +448,18 @@ def _generate(cls, start, end, periods, name, offset,
raise TypeError('Start and end cannot both be tz-aware with '
'different timezones')

inferred_tz = libts.maybe_get_tz(inferred_tz)
inferred_tz = timezones.maybe_get_tz(inferred_tz)

# these may need to be localized
tz = libts.maybe_get_tz(tz)
tz = timezones.maybe_get_tz(tz)
if tz is not None:
date = start or end
if date.tzinfo is not None and hasattr(tz, 'localize'):
tz = tz.localize(date.replace(tzinfo=None)).tzinfo

if tz is not None and inferred_tz is not None:
if not libts.get_timezone(inferred_tz) == libts.get_timezone(tz):
if not (timezones.get_timezone(inferred_tz) ==
timezones.get_timezone(tz)):
raise AssertionError("Inferred time zone not equal to passed "
"time zone")

Expand Down Expand Up @@ -593,7 +595,7 @@ def _simple_new(cls, values, name=None, freq=None, tz=None,
result._data = values
result.name = name
result.offset = freq
result.tz = libts.maybe_get_tz(tz)
result.tz = timezones.maybe_get_tz(tz)
result._reset_identity()
return result

Expand All @@ -607,7 +609,7 @@ def tzinfo(self):
@cache_readonly
def _timezone(self):
""" Comparable timezone both for pytz / dateutil"""
return libts.get_timezone(self.tzinfo)
return timezones.get_timezone(self.tzinfo)

def _has_same_tz(self, other):
zzone = self._timezone
Expand All @@ -616,7 +618,7 @@ def _has_same_tz(self, other):
if isinstance(other, np.datetime64):
# convert to Timestamp as np.datetime64 doesn't have tz attr
other = Timestamp(other)
vzone = libts.get_timezone(getattr(other, 'tzinfo', '__no_tz__'))
vzone = timezones.get_timezone(getattr(other, 'tzinfo', '__no_tz__'))
return zzone == vzone

@classmethod
Expand Down Expand Up @@ -1779,7 +1781,7 @@ def tz_convert(self, tz):
TypeError
If DatetimeIndex is tz-naive.
"""
tz = libts.maybe_get_tz(tz)
tz = timezones.maybe_get_tz(tz)

if self.tz is None:
# tz naive, use tz_localize
Expand Down Expand Up @@ -1839,7 +1841,7 @@ def tz_localize(self, tz, ambiguous='raise', errors='raise'):
else:
raise TypeError("Already tz-aware, use tz_convert to convert.")
else:
tz = libts.maybe_get_tz(tz)
tz = timezones.maybe_get_tz(tz)
# Convert to UTC

new_dates = libts.tz_localize_to_utc(self.asi8, tz,
Expand Down
3 changes: 2 additions & 1 deletion pandas/core/tools/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections import MutableMapping

from pandas._libs import lib, tslib
from pandas._libs.tslibs.timezones import get_timezone

from pandas.core.dtypes.common import (
_ensure_object,
Expand Down Expand Up @@ -44,7 +45,7 @@ def _infer_tzinfo(start, end):
def _infer(a, b):
tz = a.tzinfo
if b and b.tzinfo:
if not (tslib.get_timezone(tz) == tslib.get_timezone(b.tzinfo)):
if not (get_timezone(tz) == get_timezone(b.tzinfo)):
raise AssertionError('Inputs must both have the same timezone,'
' {timezone1} != {timezone2}'
.format(timezone1=tz, timezone2=b.tzinfo))
Expand Down
7 changes: 4 additions & 3 deletions pandas/io/pytables.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
from pandas.core.config import get_option
from pandas.core.computation.pytables import Expr, maybe_expression

from pandas._libs import tslib, algos, lib
from pandas._libs import algos, lib
from pandas._libs.tslibs import timezones

from distutils.version import LooseVersion

Expand Down Expand Up @@ -4379,7 +4380,7 @@ def _get_info(info, name):

def _get_tz(tz):
""" for a tz-aware type, return an encoded zone """
zone = tslib.get_timezone(tz)
zone = timezones.get_timezone(tz)
if zone is None:
zone = tz.utcoffset().total_seconds()
return zone
Expand All @@ -4401,7 +4402,7 @@ def _set_tz(values, tz, preserve_UTC=False, coerce=False):
if tz is not None:
name = getattr(values, 'name', None)
values = values.ravel()
tz = tslib.get_timezone(_ensure_decoded(tz))
tz = timezones.get_timezone(_ensure_decoded(tz))
values = DatetimeIndex(values, name=name)
if values.tz is None:
values = values.tz_localize('UTC').tz_convert(tz)
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/indexes/datetimes/test_date_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ def test_range_tz_dateutil(self):
# see gh-2906

# Use maybe_get_tz to fix filename in tz under dateutil.
from pandas._libs.tslib import maybe_get_tz
from pandas._libs.tslibs.timezones import maybe_get_tz
tz = lambda x: maybe_get_tz('dateutil/' + x)

start = datetime(2011, 1, 1, tzinfo=tz('US/Eastern'))
Expand Down
Loading