diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index 4e2c428415926..590fde2aaccf8 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -2149,12 +2149,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 class:`datetime.timezone` +objects from the standard library. -.. note:: - - pandas does not yet support ``datetime.timezone`` objects from the standard - library. Working with Time Zones ~~~~~~~~~~~~~~~~~~~~~~~ @@ -2197,6 +2194,15 @@ 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) + 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 1d2466adf9265..9df9327c7b7ea 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -27,6 +27,7 @@ Other Enhancements - :meth:`DatetimeIndex.union` now supports the ``sort`` argument. The behaviour of the sort parameter matches that of :meth:`Index.union` (:issue:`24994`) - :meth:`DataFrame.rename` now supports the ``errors`` argument to raise errors when attempting to rename nonexistent keys (:issue:`13473`) - :class:`RangeIndex` has gained :attr:`~RangeIndex.start`, :attr:`~RangeIndex.stop`, and :attr:`~RangeIndex.step` attributes (:issue:`25710`) +- :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 43a35d77dd127..f56bcf93f1689 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 ( @@ -23,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 object utc_stdlib = timezone.utc # ---------------------------------------------------------------------- cpdef inline bint is_utc(object tz): - return tz is UTC 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): @@ -167,6 +169,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 diff --git a/pandas/conftest.py b/pandas/conftest.py index 35a6b5df35ddc..acda660edf84b 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 @@ -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) @@ -366,7 +364,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)) 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 26dcf7d6bc234..773bb91e39376 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -416,9 +416,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