From 005ee9a44cf2355a50aa693b43db23674d38b2b0 Mon Sep 17 00:00:00 2001 From: Alice Harpole Date: Fri, 1 Sep 2017 13:34:23 +0200 Subject: [PATCH 1/5] DEPS: Added tz keywords to to_datetime, deprecated utc closes #13712 --- pandas/core/tools/datetimes.py | 22 +++++++++++++------- pandas/tests/indexes/datetimes/test_tools.py | 12 +++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index c0f234a36803d..5af09b0e410eb 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -20,6 +20,7 @@ ABCDataFrame, ABCDateOffset) from pandas.core.dtypes.missing import notna from pandas.core import algorithms +from pandas.util._decorators import deprecate_kwarg import pandas.compat as compat @@ -181,10 +182,12 @@ def _guess_datetime_format_for_array(arr, **kwargs): if len(non_nan_elements): return _guess_datetime_format(arr[non_nan_elements[0]], **kwargs) - +@deprecate_kwarg(old_arg_name='utc', new_arg_name='tz', + mapping={True: 'UTC'}) def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, - utc=None, box=True, format=None, exact=True, - unit=None, infer_datetime_format=False, origin='unix'): + box=True, format=None, exact=True, + unit=None, infer_datetime_format=False, origin='unix', + tz=None): """ Convert argument to datetime. @@ -221,8 +224,13 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, .. versionadded: 0.16.1 utc : boolean, default None + .. deprecated Return UTC DatetimeIndex if True (converting any tz-aware datetime.datetime objects as well). + tz : pytz.timezone or dateutil.tz.tzfile, default None + Define the timezone. + + .. versionadded box : boolean, default True - If True returns a DatetimeIndex @@ -343,8 +351,6 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, """ from pandas.core.indexes.datetimes import DatetimeIndex - tz = 'utc' if utc else None - def _convert_listlike(arg, box, format, name=None, tz=tz): if isinstance(arg, (list, tuple)): @@ -354,8 +360,6 @@ def _convert_listlike(arg, box, format, name=None, tz=tz): if is_datetime64tz_dtype(arg): if not isinstance(arg, DatetimeIndex): return DatetimeIndex(arg, tz=tz, name=name) - if utc: - arg = arg.tz_convert(None).tz_localize('UTC') return arg elif is_datetime64_ns_dtype(arg): @@ -431,6 +435,10 @@ def _convert_listlike(arg, box, format, name=None, tz=tz): result = arg if result is None and (format is None or infer_datetime_format): + if tz == 'utc' or tz == 'UTC': + utc = True + else: + utc = False result = tslib.array_to_datetime( arg, errors=errors, diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index 50669ee357bbd..7409108f54810 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -270,6 +270,18 @@ def test_to_datetime_utc_is_true(self): expected = pd.DatetimeIndex(data=date_range) tm.assert_index_equal(result, expected) + def test_to_datetime_tz(self): + # See gh-13712 + for tz in [None, 'US/Eastern', 'Asia/Tokyo', 'UTC']: + start = pd.Timestamp('2014-01-01', tz=tz) + end = pd.Timestamp('2014-01-03', tz=tz) + date_range = pd.bdate_range(start, end) + + result = pd.to_datetime(date_range, tz=tz) + expected = pd.DatetimeIndex(data=date_range) + tm.assert_index_equal(result, expected) + assert result.tz == expected.tz + def test_to_datetime_tz_psycopg2(self): # xref 8260 From 63be2eaf5b3e8b1d1b6334b9a5b2dcd755db4d3e Mon Sep 17 00:00:00 2001 From: Alice Harpole Date: Fri, 1 Sep 2017 13:44:06 +0200 Subject: [PATCH 2/5] Fixed formatting so passes flake8 --- pandas/core/tools/datetimes.py | 1 + pandas/tests/indexes/datetimes/test_tools.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 5af09b0e410eb..f9321764f7d7e 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -182,6 +182,7 @@ def _guess_datetime_format_for_array(arr, **kwargs): if len(non_nan_elements): return _guess_datetime_format(arr[non_nan_elements[0]], **kwargs) + @deprecate_kwarg(old_arg_name='utc', new_arg_name='tz', mapping={True: 'UTC'}) def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index 7409108f54810..8e66f940b6873 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -270,7 +270,7 @@ def test_to_datetime_utc_is_true(self): expected = pd.DatetimeIndex(data=date_range) tm.assert_index_equal(result, expected) - def test_to_datetime_tz(self): + def test_to_datetime_tz_kw(self): # See gh-13712 for tz in [None, 'US/Eastern', 'Asia/Tokyo', 'UTC']: start = pd.Timestamp('2014-01-01', tz=tz) From b768873dc0df9a3b752c4e1a440da5d912186c2f Mon Sep 17 00:00:00 2001 From: Alice Harpole Date: Fri, 1 Sep 2017 13:57:00 +0200 Subject: [PATCH 3/5] Added changes to whatsnew --- doc/source/whatsnew/v0.21.0.txt | 5 ++++- pandas/core/tools/datetimes.py | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 273cbd8357f85..96e21852e9189 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -132,7 +132,6 @@ Other Enhancements - :func:`DataFrame.items` and :func:`Series.items` is now present in both Python 2 and 3 and is lazy in all cases (:issue:`13918`, :issue:`17213`) - .. _whatsnew_0210.api_breaking: Backwards incompatible API changes @@ -328,6 +327,10 @@ Deprecations - ``pd.options.html.border`` has been deprecated in favor of ``pd.options.display.html.border`` (:issue:`15793`). + +- :func: `to_datetime` now takes ``tz`` keyword argument, ``utc`` argument is deprecated (:issue:`13712`) + + .. _whatsnew_0210.prior_deprecations: Removal of prior version deprecations/changes diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index f9321764f7d7e..0b468e0a057e9 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -225,13 +225,16 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, .. versionadded: 0.16.1 utc : boolean, default None - .. deprecated Return UTC DatetimeIndex if True (converting any tz-aware datetime.datetime objects as well). + + .. deprecated: 0.21.0 + tz : pytz.timezone or dateutil.tz.tzfile, default None Define the timezone. - .. versionadded + .. versionadded: 0.21.0 + box : boolean, default True - If True returns a DatetimeIndex From fabeb9644b3434e3abebcf0ef919577369b72b34 Mon Sep 17 00:00:00 2001 From: Alice Harpole Date: Fri, 1 Sep 2017 14:02:56 +0200 Subject: [PATCH 4/5] BUG: Removed whitespace so code obeys PEP8 --- pandas/core/tools/datetimes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 0b468e0a057e9..4ca67d890dc35 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -234,7 +234,7 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, Define the timezone. .. versionadded: 0.21.0 - + box : boolean, default True - If True returns a DatetimeIndex From aec8db29f51715de340462201e6cbf804548212a Mon Sep 17 00:00:00 2001 From: Alice Harpole Date: Fri, 1 Sep 2017 15:50:41 +0200 Subject: [PATCH 5/5] Fixed test so it initialises from a numpy array and checks the zone name rather than the timezone --- pandas/core/tools/datetimes.py | 2 ++ pandas/tests/indexes/datetimes/test_tools.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 4ca67d890dc35..dc388fe4e1a55 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -364,6 +364,8 @@ def _convert_listlike(arg, box, format, name=None, tz=tz): if is_datetime64tz_dtype(arg): if not isinstance(arg, DatetimeIndex): return DatetimeIndex(arg, tz=tz, name=name) + if tz: + arg = arg.tz_convert(None).tz_localize(tz) return arg elif is_datetime64_ns_dtype(arg): diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index 8e66f940b6873..98ce7e32cc4b9 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -273,14 +273,19 @@ def test_to_datetime_utc_is_true(self): def test_to_datetime_tz_kw(self): # See gh-13712 for tz in [None, 'US/Eastern', 'Asia/Tokyo', 'UTC']: - start = pd.Timestamp('2014-01-01', tz=tz) - end = pd.Timestamp('2014-01-03', tz=tz) + data = ['20140101 000000', '20140102 000000', '20140103 000000'] + start = pd.Timestamp(data[0], tz=tz) + end = pd.Timestamp(data[-1], tz=tz) date_range = pd.bdate_range(start, end) - result = pd.to_datetime(date_range, tz=tz) + result = pd.to_datetime(data, format='%Y%m%d %H%M%S', tz=tz) expected = pd.DatetimeIndex(data=date_range) - tm.assert_index_equal(result, expected) - assert result.tz == expected.tz + tm.assert_numpy_array_equal(result.values, expected.values) + + if result.tz is None: + assert expected.tz is None + else: + assert result.tz.zone == expected.tz.zone def test_to_datetime_tz_psycopg2(self):