Skip to content

Commit 328c7e1

Browse files
jbrockmendeljreback
authored andcommitted
Cut/paste (most) remaining tz funcs to tslibs/timezones (#17526)
1 parent 72c3888 commit 328c7e1

File tree

5 files changed

+225
-192
lines changed

5 files changed

+225
-192
lines changed

pandas/_libs/period.pyx

+3-5
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,9 @@ from lib cimport is_null_datetimelike, is_period
3434
from pandas._libs import tslib, lib
3535
from pandas._libs.tslib import (Timedelta, Timestamp, iNaT,
3636
NaT)
37-
from tslibs.timezones cimport is_utc, is_tzlocal, get_utcoffset
38-
from tslib cimport (
39-
maybe_get_tz,
40-
_get_dst_info,
41-
_nat_scalar_rules)
37+
from tslibs.timezones cimport (
38+
is_utc, is_tzlocal, get_utcoffset, _get_dst_info, maybe_get_tz)
39+
from tslib cimport _nat_scalar_rules
4240

4341
from tslibs.frequencies cimport get_freq_code
4442

pandas/_libs/tslib.pxd

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@ from numpy cimport ndarray, int64_t
22

33
cdef convert_to_tsobject(object, object, object, bint, bint)
44
cpdef convert_to_timedelta64(object, object)
5-
cpdef object maybe_get_tz(object)
6-
cdef object _get_dst_info(object)
75
cdef bint _nat_scalar_rules[6]
86
cdef bint _check_all_nulls(obj)

pandas/_libs/tslib.pyx

+11-183
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ from cpython cimport (
2121
PyObject_RichCompare,
2222
Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE,
2323
PyUnicode_Check,
24-
PyUnicode_AsUTF8String,
25-
)
24+
PyUnicode_AsUTF8String)
2625

2726
cdef extern from "Python.h":
2827
cdef PyTypeObject *Py_TYPE(object)
@@ -73,19 +72,12 @@ import re
7372

7473
# dateutil compat
7574
from dateutil.tz import (tzoffset, tzlocal as _dateutil_tzlocal,
76-
tzfile as _dateutil_tzfile,
7775
tzutc as _dateutil_tzutc,
7876
tzstr as _dateutil_tzstr)
7977

80-
from pandas.compat import is_platform_windows
81-
if is_platform_windows():
82-
from dateutil.zoneinfo import gettz as _dateutil_gettz
83-
else:
84-
from dateutil.tz import gettz as _dateutil_gettz
8578
from dateutil.relativedelta import relativedelta
8679
from dateutil.parser import DEFAULTPARSER
8780

88-
from pytz.tzinfo import BaseTzInfo as _pytz_BaseTzInfo
8981
from pandas.compat import (parse_date, string_types, iteritems,
9082
StringIO, callable)
9183

@@ -108,11 +100,17 @@ iNaT = NPY_NAT
108100

109101

110102
from tslibs.timezones cimport (
111-
is_utc, is_tzlocal,
103+
is_utc, is_tzlocal, _is_fixed_offset,
112104
treat_tz_as_dateutil, treat_tz_as_pytz,
113-
get_timezone,
114-
get_utcoffset)
115-
from tslibs.timezones import get_timezone, get_utcoffset # noqa
105+
get_timezone, get_utcoffset, maybe_get_tz,
106+
_get_dst_info
107+
)
108+
from tslibs.timezones import ( # noqa
109+
get_timezone, get_utcoffset, maybe_get_tz,
110+
_p_tz_cache_key, dst_cache,
111+
_unbox_utcoffsets,
112+
_dateutil_gettz
113+
)
116114

117115

118116
cdef inline object create_timestamp_from_ts(
@@ -241,20 +239,6 @@ def ints_to_pytimedelta(ndarray[int64_t] arr, box=False):
241239
return result
242240

243241

244-
cdef inline bint _is_fixed_offset(object tz):
245-
if treat_tz_as_dateutil(tz):
246-
if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0:
247-
return 1
248-
else:
249-
return 0
250-
elif treat_tz_as_pytz(tz):
251-
if (len(tz._transition_info) == 0
252-
and len(tz._utc_transition_times) == 0):
253-
return 1
254-
else:
255-
return 0
256-
return 1
257-
258242
_zero_time = datetime_time(0, 0)
259243
_no_input = object()
260244

@@ -1709,27 +1693,6 @@ def _localize_pydatetime(object dt, object tz):
17091693
return dt.replace(tzinfo=tz)
17101694

17111695

1712-
cpdef inline object maybe_get_tz(object tz):
1713-
"""
1714-
(Maybe) Construct a timezone object from a string. If tz is a string, use
1715-
it to construct a timezone object. Otherwise, just return tz.
1716-
"""
1717-
if isinstance(tz, string_types):
1718-
if tz == 'tzlocal()':
1719-
tz = _dateutil_tzlocal()
1720-
elif tz.startswith('dateutil/'):
1721-
zone = tz[9:]
1722-
tz = _dateutil_gettz(zone)
1723-
# On Python 3 on Windows, the filename is not always set correctly.
1724-
if isinstance(tz, _dateutil_tzfile) and '.tar.gz' in tz._filename:
1725-
tz._filename = zone
1726-
else:
1727-
tz = pytz.timezone(tz)
1728-
elif is_integer_object(tz):
1729-
tz = pytz.FixedOffset(tz / 60)
1730-
return tz
1731-
1732-
17331696
class OutOfBoundsDatetime(ValueError):
17341697
pass
17351698

@@ -4237,141 +4200,6 @@ def tz_convert_single(int64_t val, object tz1, object tz2):
42374200
offset = deltas[pos]
42384201
return utc_date + offset
42394202

4240-
# Timezone data caches, key is the pytz string or dateutil file name.
4241-
dst_cache = {}
4242-
4243-
4244-
def _p_tz_cache_key(tz):
4245-
""" Python interface for cache function to facilitate testing."""
4246-
return _tz_cache_key(tz)
4247-
4248-
4249-
cdef inline object _tz_cache_key(object tz):
4250-
"""
4251-
Return the key in the cache for the timezone info object or None
4252-
if unknown.
4253-
4254-
The key is currently the tz string for pytz timezones, the filename for
4255-
dateutil timezones.
4256-
4257-
Notes
4258-
=====
4259-
This cannot just be the hash of a timezone object. Unfortunately, the
4260-
hashes of two dateutil tz objects which represent the same timezone are
4261-
not equal (even though the tz objects will compare equal and represent
4262-
the same tz file). Also, pytz objects are not always hashable so we use
4263-
str(tz) instead.
4264-
"""
4265-
if isinstance(tz, _pytz_BaseTzInfo):
4266-
return tz.zone
4267-
elif isinstance(tz, _dateutil_tzfile):
4268-
if '.tar.gz' in tz._filename:
4269-
raise ValueError('Bad tz filename. Dateutil on python 3 on '
4270-
'windows has a bug which causes tzfile._filename '
4271-
'to be the same for all timezone files. Please '
4272-
'construct dateutil timezones implicitly by '
4273-
'passing a string like "dateutil/Europe/London" '
4274-
'when you construct your pandas objects instead '
4275-
'of passing a timezone object. See '
4276-
'https://github.com/pandas-dev/pandas/pull/7362')
4277-
return 'dateutil' + tz._filename
4278-
else:
4279-
return None
4280-
4281-
4282-
cdef object _get_dst_info(object tz):
4283-
"""
4284-
return a tuple of :
4285-
(UTC times of DST transitions,
4286-
UTC offsets in microseconds corresponding to DST transitions,
4287-
string of type of transitions)
4288-
4289-
"""
4290-
cache_key = _tz_cache_key(tz)
4291-
if cache_key is None:
4292-
num = int(get_utcoffset(tz, None).total_seconds()) * 1000000000
4293-
return (np.array([NPY_NAT + 1], dtype=np.int64),
4294-
np.array([num], dtype=np.int64),
4295-
None)
4296-
4297-
if cache_key not in dst_cache:
4298-
if treat_tz_as_pytz(tz):
4299-
trans = np.array(tz._utc_transition_times, dtype='M8[ns]')
4300-
trans = trans.view('i8')
4301-
try:
4302-
if tz._utc_transition_times[0].year == 1:
4303-
trans[0] = NPY_NAT + 1
4304-
except Exception:
4305-
pass
4306-
deltas = _unbox_utcoffsets(tz._transition_info)
4307-
typ = 'pytz'
4308-
4309-
elif treat_tz_as_dateutil(tz):
4310-
if len(tz._trans_list):
4311-
# get utc trans times
4312-
trans_list = _get_utc_trans_times_from_dateutil_tz(tz)
4313-
trans = np.hstack([
4314-
np.array([0], dtype='M8[s]'), # place holder for first item
4315-
np.array(trans_list, dtype='M8[s]')]).astype(
4316-
'M8[ns]') # all trans listed
4317-
trans = trans.view('i8')
4318-
trans[0] = NPY_NAT + 1
4319-
4320-
# deltas
4321-
deltas = np.array([v.offset for v in (
4322-
tz._ttinfo_before,) + tz._trans_idx], dtype='i8')
4323-
deltas *= 1000000000
4324-
typ = 'dateutil'
4325-
4326-
elif _is_fixed_offset(tz):
4327-
trans = np.array([NPY_NAT + 1], dtype=np.int64)
4328-
deltas = np.array([tz._ttinfo_std.offset],
4329-
dtype='i8') * 1000000000
4330-
typ = 'fixed'
4331-
else:
4332-
trans = np.array([], dtype='M8[ns]')
4333-
deltas = np.array([], dtype='i8')
4334-
typ = None
4335-
4336-
else:
4337-
# static tzinfo
4338-
trans = np.array([NPY_NAT + 1], dtype=np.int64)
4339-
num = int(get_utcoffset(tz, None).total_seconds()) * 1000000000
4340-
deltas = np.array([num], dtype=np.int64)
4341-
typ = 'static'
4342-
4343-
dst_cache[cache_key] = (trans, deltas, typ)
4344-
4345-
return dst_cache[cache_key]
4346-
4347-
cdef object _get_utc_trans_times_from_dateutil_tz(object tz):
4348-
"""
4349-
Transition times in dateutil timezones are stored in local non-dst
4350-
time. This code converts them to UTC. It's the reverse of the code
4351-
in dateutil.tz.tzfile.__init__.
4352-
"""
4353-
new_trans = list(tz._trans_list)
4354-
last_std_offset = 0
4355-
for i, (trans, tti) in enumerate(zip(tz._trans_list, tz._trans_idx)):
4356-
if not tti.isdst:
4357-
last_std_offset = tti.offset
4358-
new_trans[i] = trans - last_std_offset
4359-
return new_trans
4360-
4361-
4362-
cpdef ndarray _unbox_utcoffsets(object transinfo):
4363-
cdef:
4364-
Py_ssize_t i, sz
4365-
ndarray[int64_t] arr
4366-
4367-
sz = len(transinfo)
4368-
arr = np.empty(sz, dtype='i8')
4369-
4370-
for i in range(sz):
4371-
arr[i] = int(transinfo[i][0].total_seconds()) * 1000000000
4372-
4373-
return arr
4374-
43754203

43764204
@cython.boundscheck(False)
43774205
@cython.wraparound(False)

pandas/_libs/tslibs/timezones.pxd

+6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
# -*- coding: utf-8 -*-
22
# cython: profile=False
33

4+
from numpy cimport ndarray
5+
46
cdef bint is_utc(object tz)
57
cdef bint is_tzlocal(object tz)
68

79
cdef bint treat_tz_as_pytz(object tz)
810
cdef bint treat_tz_as_dateutil(object tz)
911

1012
cpdef object get_timezone(object tz)
13+
cpdef object maybe_get_tz(object tz)
1114

1215
cpdef get_utcoffset(tzinfo, obj)
16+
cdef bint _is_fixed_offset(object tz)
17+
18+
cdef object _get_dst_info(object tz)

0 commit comments

Comments
 (0)