From e28680b0012f60348c7eff68553f003f2fd15909 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sat, 5 Sep 2015 13:48:08 -0400 Subject: [PATCH 1/2] DOC: fix up docs a bit for datetime64[ns, tz] --- doc/source/timeseries.rst | 45 +++++++++++++++++++++++++-------- doc/source/whatsnew/v0.17.0.txt | 11 +++++--- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/doc/source/timeseries.rst b/doc/source/timeseries.rst index dd13e8fabf0e9..c77715182dc04 100644 --- a/doc/source/timeseries.rst +++ b/doc/source/timeseries.rst @@ -1753,22 +1753,45 @@ TZ aware Dtypes .. versionadded:: 0.17.0 -``Series/DatetimeIndex`` with a timezone naive value are represented with a dtype of ``datetime64[ns]``. +``Series/DatetimeIndex`` with a timezone **naive** value are represented with a dtype of ``datetime64[ns]``. .. ipython:: python - dr = pd.date_range('20130101',periods=3) - dr - s = Series(dr) - s + dr_naive = pd.date_range('20130101',periods=3) + dr_naive + s_naive = Series(dr_naive) + s_naive -``Series/DatetimeIndex`` with a timezone aware value are represented with a dtype of ``datetime64[ns, tz]``. +``Series/DatetimeIndex`` with a timezone **aware** value are represented with a dtype of ``datetime64[ns, tz]``. .. ipython:: python - dr = pd.date_range('20130101',periods=3,tz='US/Eastern') - dr - s = Series(dr) - s + dr_aware = pd.date_range('20130101',periods=3,tz='US/Eastern') + dr_aware + s_aware = Series(dr_aware) + s_aware + +Both of these ``Series`` can be manipulated via the ``.dt`` accessor, see :ref:`here `. +See the :ref:`docs ` for more details. + +.. note:: + + Using the ``.values`` accessor on a ``Series``, returns an numpy array of the data. + These values are converted to UTC, as numpy does not currently support timezones (even though it is *printing* in the local timezone!). + + .. ipython:: python + + s_naive.values + s_aware.values + + Further note that once converted to a numpy array these would lose the tz tenor. + + .. ipython:: python + + Series(s_aware.values) + + However, these can be easily converted + + .. ipython:: python -Both of these ``Series`` can be manipulated via the ``.dt`` accessor, see the :ref:`docs ` as well. + Series(s_aware).dt.tz_localize('UTC').dt.tz_convert('US/Eastern') diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index f88e5c0a11f9f..9eb005a604b0c 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -447,9 +447,9 @@ Datetime with TZ We are adding an implementation that natively supports datetime with timezones. A ``Series`` or a ``DataFrame`` column previously *could* be assigned a datetime with timezones, and would work as an ``object`` dtype. This had performance issues with a large -number rows. (:issue:`8260`, :issue:`10763`) +number rows. See the :ref:`docs ` for more details. (:issue:`8260`, :issue:`10763`). -The new implementation allows for having a single-timezone across all rows, and operating on it in a performant manner. +The new implementation allows for having a single-timezone across all rows, with operations in a performant manner. .. ipython:: python @@ -469,13 +469,15 @@ This uses a new-dtype representation as well, that is very similar in look-and-f .. ipython:: python df['B'].dtype - type(df['B']).dtype + type(df['B'].dtype) .. note:: There is a slightly different string repr for the underlying ``DatetimeIndex`` as a result of the dtype changes, but functionally these are the same. + Previous Behavior: + .. code-block:: python In [1]: pd.date_range('20130101',periods=3,tz='US/Eastern') @@ -486,12 +488,13 @@ This uses a new-dtype representation as well, that is very similar in look-and-f In [2]: pd.date_range('20130101',periods=3,tz='US/Eastern').dtype Out[2]: dtype(' Date: Sat, 5 Sep 2015 14:07:24 -0400 Subject: [PATCH 2/2] add .astype('datetime64[ns, tz]') ability --- doc/source/timeseries.rst | 11 +++++++++++ pandas/core/internals.py | 21 +++++++++++++++++++++ pandas/tests/test_series.py | 14 ++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/doc/source/timeseries.rst b/doc/source/timeseries.rst index c77715182dc04..7e96fdad29193 100644 --- a/doc/source/timeseries.rst +++ b/doc/source/timeseries.rst @@ -1774,6 +1774,17 @@ TZ aware Dtypes Both of these ``Series`` can be manipulated via the ``.dt`` accessor, see :ref:`here `. See the :ref:`docs ` for more details. +Further more you can ``.astype(...)`` timezone aware (and naive). + +.. ipython:: python + + # make this naive + s_aware.astype('datetime64[ns]') + + # convert + s_aware.astype('datetime64[ns, CET]') + s_naive.astype('datetime64[ns, CET]') + .. note:: Using the ``.values`` accessor on a ``Series``, returns an numpy array of the data. diff --git a/pandas/core/internals.py b/pandas/core/internals.py index 58ee36142d4fd..94eccad8e0185 100644 --- a/pandas/core/internals.py +++ b/pandas/core/internals.py @@ -18,6 +18,7 @@ array_equivalent, _maybe_convert_string_to_object, is_categorical, needs_i8_conversion, is_datetimelike_v_numeric, is_internal_type) +from pandas.core.dtypes import DatetimeTZDtype from pandas.core.index import Index, MultiIndex, _ensure_index from pandas.core.indexing import maybe_convert_indices, length_of_indexer @@ -1868,6 +1869,26 @@ def __init__(self, values, placement, fastpath=True, placement=placement, **kwargs) + def _astype(self, dtype, **kwargs): + """ + these automatically copy, so copy=True has no effect + raise on an except if raise == True + """ + + # if we are passed a datetime64[ns, tz] + if com.is_datetime64tz_dtype(dtype): + dtype = DatetimeTZDtype(dtype) + + values = self.values + if getattr(values,'tz',None) is None: + values = DatetimeIndex(values).tz_localize('UTC') + values = values.tz_convert(dtype.tz) + return self.make_block(values) + + # delegate + return super(DatetimeBlock, self)._astype(dtype=dtype, **kwargs) + + def _can_hold_element(self, element): if is_list_like(element): element = np.array(element) diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 8da821a1fbb9a..0794ae5003983 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -1072,6 +1072,20 @@ def test_constructor_with_datetime_tz(self): expected = Series(DatetimeIndex(s._values).asobject) assert_series_equal(result, expected) + result = Series(s.values).dt.tz_localize('UTC').dt.tz_convert(s.dt.tz) + assert_series_equal(result, s) + + # astype - datetime64[ns, tz] + result = Series(s.values).astype('datetime64[ns, US/Eastern]') + assert_series_equal(result, s) + + result = Series(s.values).astype(s.dtype) + assert_series_equal(result, s) + + result = s.astype('datetime64[ns, CET]') + expected = Series(date_range('20130101 06:00:00',periods=3,tz='CET')) + assert_series_equal(result, expected) + # short str self.assertTrue('datetime64[ns, US/Eastern]' in str(s))