From 8ff80240de5bb83771ad0ea3b8610a85ab964c7b Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 29 Jan 2019 23:54:51 -0800 Subject: [PATCH 01/13] ENH: Support datetime.timezone objects --- pandas/_libs/tslibs/timezones.pyx | 7 +++++-- pandas/conftest.py | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 43a35d77dd127..d5c36ebe76a6a 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from datetime import timezone # dateutil compat from dateutil.tz import ( @@ -27,7 +28,7 @@ cdef int64_t NPY_NAT = get_nat() # ---------------------------------------------------------------------- cpdef inline bint is_utc(object tz): - return tz is UTC or isinstance(tz, _dateutil_tzutc) + return tz is UTC or isinstance(tz, _dateutil_tzutc) or tz is timezone.utc cdef inline bint is_tzlocal(object tz): @@ -156,7 +157,9 @@ cdef get_utcoffset(tzinfo, obj): cdef inline bint is_fixed_offset(object tz): - if treat_tz_as_dateutil(tz): + if isinstance(tz, timezone): + return 1 + elif treat_tz_as_dateutil(tz): if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0: return 1 else: diff --git a/pandas/conftest.py b/pandas/conftest.py index 35a6b5df35ddc..c0dc0ffbb6d40 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -1,4 +1,4 @@ -from datetime import date, time, timedelta +from datetime import date, time, timedelta, timezone from decimal import Decimal import os @@ -366,7 +366,9 @@ def unique_nulls_fixture(request): TIMEZONES = [None, 'UTC', 'US/Eastern', 'Asia/Tokyo', 'dateutil/US/Pacific', 'dateutil/Asia/Singapore', tzutc(), tzlocal(), FixedOffset(300), - FixedOffset(0), FixedOffset(-300)] + FixedOffset(0), FixedOffset(-300), timezone.utc, + timezone(timedelta(hours=1)), + timezone(timedelta(hours=-1), name='foo')] @td.parametrize_fixture_doc(str(TIMEZONES)) From 8ff047b88261b281c3923ec43b3cd83a080b40d8 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Thu, 31 Jan 2019 15:38:49 -0800 Subject: [PATCH 02/13] add comment and simplify check --- pandas/_libs/tslibs/timezones.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index d5c36ebe76a6a..79b8c06f0318e 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -157,9 +157,7 @@ cdef get_utcoffset(tzinfo, obj): cdef inline bint is_fixed_offset(object tz): - if isinstance(tz, timezone): - return 1 - elif treat_tz_as_dateutil(tz): + if treat_tz_as_dateutil(tz): if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0: return 1 else: @@ -170,6 +168,8 @@ cdef inline bint is_fixed_offset(object tz): return 1 else: return 0 + # This also implicitly accepts datetime.timezone objects which are + # considered fixed return 1 From 50760456c6537e6e8b918a8b27b0cedb87629158 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Thu, 31 Jan 2019 19:55:08 -0800 Subject: [PATCH 03/13] flake8 and modify check --- pandas/conftest.py | 2 -- pandas/tests/indexes/datetimes/test_construction.py | 4 ++-- pandas/tests/indexes/test_base.py | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index c0dc0ffbb6d40..acda660edf84b 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -247,13 +247,11 @@ def writable(request): @pytest.fixture(scope='module') def datetime_tz_utc(): - from datetime import timezone return timezone.utc utc_objs = ['utc', 'dateutil/UTC', utc, tzutc()] if PY3: - from datetime import timezone utc_objs.append(timezone.utc) diff --git a/pandas/tests/indexes/datetimes/test_construction.py b/pandas/tests/indexes/datetimes/test_construction.py index 6893f635c82ac..422184b7e80a2 100644 --- a/pandas/tests/indexes/datetimes/test_construction.py +++ b/pandas/tests/indexes/datetimes/test_construction.py @@ -1,4 +1,4 @@ -from datetime import timedelta +from datetime import timedelta, timezone from functools import partial from operator import attrgetter @@ -119,7 +119,7 @@ def test_construction_with_alt_tz_localize(self, kwargs, tz_aware_fixture): i = pd.date_range('20130101', periods=5, freq='H', tz=tz) kwargs = {key: attrgetter(val)(i) for key, val in kwargs.items()} - if str(tz) in ('UTC', 'tzutc()'): + if str(tz) in ('UTC', 'tzutc()') or tz is timezone.utc: warn = None else: warn = FutureWarning diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 20e439de46bde..ebbc4f726e90c 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from collections import defaultdict -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import math import sys @@ -413,7 +413,8 @@ def test_constructor_dtypes_datetime(self, tz_naive_fixture, attr, utc, modules = [sys.modules['pandas.core.indexes.base']] if (tz_naive_fixture and attr == "asi8" and - str(tz_naive_fixture) not in ('UTC', 'tzutc()')): + (str(tz_naive_fixture) not in ('UTC', 'tzutc()') + or tz_naive_fixture is not timezone.utc)): ex_warn = FutureWarning else: ex_warn = None From f819b2684c76d0fe4ae4fe5319177fe5da2c4d37 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sat, 2 Feb 2019 18:46:53 -0800 Subject: [PATCH 04/13] Remove check --- pandas/tests/indexes/datetimes/test_construction.py | 4 ++-- pandas/tests/indexes/test_base.py | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_construction.py b/pandas/tests/indexes/datetimes/test_construction.py index 422184b7e80a2..6893f635c82ac 100644 --- a/pandas/tests/indexes/datetimes/test_construction.py +++ b/pandas/tests/indexes/datetimes/test_construction.py @@ -1,4 +1,4 @@ -from datetime import timedelta, timezone +from datetime import timedelta from functools import partial from operator import attrgetter @@ -119,7 +119,7 @@ def test_construction_with_alt_tz_localize(self, kwargs, tz_aware_fixture): i = pd.date_range('20130101', periods=5, freq='H', tz=tz) kwargs = {key: attrgetter(val)(i) for key, val in kwargs.items()} - if str(tz) in ('UTC', 'tzutc()') or tz is timezone.utc: + if str(tz) in ('UTC', 'tzutc()'): warn = None else: warn = FutureWarning diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index ebbc4f726e90c..20e439de46bde 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from collections import defaultdict -from datetime import datetime, timedelta, timezone +from datetime import datetime, timedelta import math import sys @@ -413,8 +413,7 @@ def test_constructor_dtypes_datetime(self, tz_naive_fixture, attr, utc, modules = [sys.modules['pandas.core.indexes.base']] if (tz_naive_fixture and attr == "asi8" and - (str(tz_naive_fixture) not in ('UTC', 'tzutc()') - or tz_naive_fixture is not timezone.utc)): + str(tz_naive_fixture) not in ('UTC', 'tzutc()')): ex_warn = FutureWarning else: ex_warn = None From 98c3fd2b91b26927f2dffd64ce40e6dbce7e5429 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sat, 2 Feb 2019 20:37:40 -0800 Subject: [PATCH 05/13] cdef timezone.utc --- pandas/_libs/tslibs/timezones.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 79b8c06f0318e..84db4a5e5da84 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -24,11 +24,12 @@ from pandas._libs.tslibs.util cimport ( is_string_object, is_integer_object, get_nat) cdef int64_t NPY_NAT = get_nat() +cdef tzinfo utc_stdlib = timezone.utc # ---------------------------------------------------------------------- cpdef inline bint is_utc(object tz): - return tz is UTC or isinstance(tz, _dateutil_tzutc) or tz is timezone.utc + return tz is UTC or isinstance(tz, _dateutil_tzutc) or tz is utc_stdlib cdef inline bint is_tzlocal(object tz): From 224fcc9618d22da2f8c8cd3f1bf1df5577b08353 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sat, 2 Feb 2019 21:28:56 -0800 Subject: [PATCH 06/13] cannot cdef tzinfo --- pandas/_libs/tslibs/timezones.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 84db4a5e5da84..eaa6b20a26b9f 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -24,7 +24,7 @@ from pandas._libs.tslibs.util cimport ( is_string_object, is_integer_object, get_nat) cdef int64_t NPY_NAT = get_nat() -cdef tzinfo utc_stdlib = timezone.utc +cdef object utc_stdlib = timezone.utc # ---------------------------------------------------------------------- From b3634f4fad669d02f9f553e0f943b65c97c87149 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sat, 2 Feb 2019 21:40:00 -0800 Subject: [PATCH 07/13] PY3.5 support --- pandas/tests/indexes/datetimes/test_construction.py | 2 +- pandas/tests/indexes/test_base.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_construction.py b/pandas/tests/indexes/datetimes/test_construction.py index 6893f635c82ac..6a13836be0dfa 100644 --- a/pandas/tests/indexes/datetimes/test_construction.py +++ b/pandas/tests/indexes/datetimes/test_construction.py @@ -119,7 +119,7 @@ def test_construction_with_alt_tz_localize(self, kwargs, tz_aware_fixture): i = pd.date_range('20130101', periods=5, freq='H', tz=tz) kwargs = {key: attrgetter(val)(i) for key, val in kwargs.items()} - if str(tz) in ('UTC', 'tzutc()'): + if str(tz) in ('UTC', 'tzutc()', 'UTC+00:00'): warn = None else: warn = FutureWarning diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 20e439de46bde..1d9bf49cabc8a 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -411,9 +411,8 @@ def test_constructor_dtypes_datetime(self, tz_naive_fixture, attr, utc, # TODO(GH-24559): Remove the sys.modules and warnings # not sure what this is from. It's Py2 only. modules = [sys.modules['pandas.core.indexes.base']] - if (tz_naive_fixture and attr == "asi8" and - str(tz_naive_fixture) not in ('UTC', 'tzutc()')): + str(tz_naive_fixture) not in ('UTC', 'tzutc()', 'UTC+00:00')): ex_warn = FutureWarning else: ex_warn = None From bfb2fd341224f3fe5cc4c66edfb73bfe09658317 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 3 Feb 2019 11:19:12 -0800 Subject: [PATCH 08/13] Add whatsnew --- doc/source/whatsnew/v0.25.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 09626be713c4f..5ae5208135d3f 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -20,7 +20,7 @@ Other Enhancements ^^^^^^^^^^^^^^^^^^ - :meth:`Timestamp.replace` now supports the ``fold`` argument to disambiguate DST transition times (:issue:`25017`) -- +- ``datetime.timezone`` objects are now supported (:issue:`25065`) - .. _whatsnew_0250.api_breaking: From a8f163e3ac326e21022d0bd464614b73250234a7 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Mon, 4 Feb 2019 13:44:29 -0800 Subject: [PATCH 09/13] clarify whatsnew --- doc/source/whatsnew/v0.25.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 5ae5208135d3f..b7989432dad18 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -20,7 +20,7 @@ Other Enhancements ^^^^^^^^^^^^^^^^^^ - :meth:`Timestamp.replace` now supports the ``fold`` argument to disambiguate DST transition times (:issue:`25017`) -- ``datetime.timezone`` objects are now supported (:issue:`25065`) +- :meth:`datetime.timezone` objects are now supported as arguments to timezone methods and constructors (:issue:`25065`) - .. _whatsnew_0250.api_breaking: From fcf84aebf448d0f61f26b6432289fad4eaf7c8a8 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Thu, 7 Feb 2019 20:33:18 -0800 Subject: [PATCH 10/13] update note in timeseries.rst --- doc/source/user_guide/timeseries.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index 5841125817d03..774f3b151390c 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -2130,12 +2130,9 @@ Time Zone Handling ------------------ pandas provides rich support for working with timestamps in different time -zones using the ``pytz`` and ``dateutil`` libraries. +zones using the ``pytz`` and ``dateutil`` libraries or ``datetime.timezone`` +objects from the standard library. -.. note:: - - pandas does not yet support ``datetime.timezone`` objects from the standard - library. Working with Time Zones ~~~~~~~~~~~~~~~~~~~~~~~ From d74673ec8dbbc3e77536b5efa70595ce803fc604 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Mon, 4 Mar 2019 20:17:13 -0800 Subject: [PATCH 11/13] Address comments --- doc/source/user_guide/timeseries.rst | 7 ++++++- doc/source/whatsnew/v0.25.0.rst | 2 +- pandas/_libs/tslibs/timezones.pyx | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index 50ea4be10ed73..d4de82606c4fd 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -2149,7 +2149,7 @@ Time Zone Handling ------------------ pandas provides rich support for working with timestamps in different time -zones using the ``pytz`` and ``dateutil`` libraries or ``datetime.timezone`` +zones using the ``pytz`` and ``dateutil`` libraries or class:`datetime.timezone` objects from the standard library. @@ -2194,6 +2194,11 @@ To return ``dateutil`` time zone objects, append ``dateutil/`` before the string tz=dateutil.tz.tzutc()) rng_utc.tz + # datetime.timezone + rng_utc = pd.date_range('3/6/2012 00:00', periods=3, freq='D', + tz=datetime.timezone.utc) + rng_utc.tz + Note that the ``UTC`` time zone is a special case in ``dateutil`` and should be constructed explicitly as an instance of ``dateutil.tz.tzutc``. You can also construct other time zones objects explicitly first. diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 4da902b889301..89faa6b2a8e5c 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -25,7 +25,7 @@ Other Enhancements - ``Series.str`` has gained :meth:`Series.str.casefold` method to removes all case distinctions present in a string (:issue:`25405`) - :meth:`DataFrame.set_index` now works for instances of ``abc.Iterator``, provided their output is of the same length as the calling frame (:issue:`22484`, :issue:`24984`) - :meth:`DatetimeIndex.union` now supports the ``sort`` argument. The behaviour of the sort parameter matches that of :meth:`Index.union` (:issue:`24994`) -- :meth:`datetime.timezone` objects are now supported as arguments to timezone methods and constructors (:issue:`25065`) +- :class:`datetime.timezone` objects are now supported as arguments to timezone methods and constructors (:issue:`25065`) .. _whatsnew_0250.api_breaking: diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index eaa6b20a26b9f..df79defd76806 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -29,7 +29,7 @@ cdef object utc_stdlib = timezone.utc # ---------------------------------------------------------------------- cpdef inline bint is_utc(object tz): - return tz is UTC or isinstance(tz, _dateutil_tzutc) or tz is utc_stdlib + return tz is UTC or or tz is utc_stdlib or isinstance(tz, _dateutil_tzutc) cdef inline bint is_tzlocal(object tz): From c0ad4b4df5fc61dd87a81051a4b81e6f7ca3c42b Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 5 Mar 2019 11:16:49 -0800 Subject: [PATCH 12/13] Remove extra or --- pandas/_libs/tslibs/timezones.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index df79defd76806..f56bcf93f1689 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -29,7 +29,7 @@ cdef object utc_stdlib = timezone.utc # ---------------------------------------------------------------------- cpdef inline bint is_utc(object tz): - return tz is UTC or or tz is utc_stdlib or isinstance(tz, _dateutil_tzutc) + return tz is UTC or tz is utc_stdlib or isinstance(tz, _dateutil_tzutc) cdef inline bint is_tzlocal(object tz): From 96e068b53cfa5dd2c400da10d51584acbb5776b6 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 5 Mar 2019 11:43:34 -0800 Subject: [PATCH 13/13] Add versionadded tag --- doc/source/user_guide/timeseries.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index d4de82606c4fd..590fde2aaccf8 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -2194,6 +2194,10 @@ To return ``dateutil`` time zone objects, append ``dateutil/`` before the string tz=dateutil.tz.tzutc()) rng_utc.tz +.. versionadded:: 0.25.0 + +.. ipython:: python + # datetime.timezone rng_utc = pd.date_range('3/6/2012 00:00', periods=3, freq='D', tz=datetime.timezone.utc)