From 8da210c81195375e4be5653767c8a038414798d4 Mon Sep 17 00:00:00 2001 From: rockg Date: Sun, 3 Aug 2014 15:36:41 -0400 Subject: [PATCH] Remove from start/end dates if tz is not None (remove check of inferred_tz). --- doc/source/timeseries.rst | 6 ++++ doc/source/v0.15.0.txt | 4 ++- pandas/tseries/index.py | 2 +- pandas/tseries/tests/test_daterange.py | 38 ++++++++++++++++++++++---- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/doc/source/timeseries.rst b/doc/source/timeseries.rst index 05fd82b2f448d..9dd7845864e59 100644 --- a/doc/source/timeseries.rst +++ b/doc/source/timeseries.rst @@ -1364,6 +1364,12 @@ tz-aware data to another time zone: is localized using one version and operated on with a different version. See :ref:`here` for how to handle such a situation. +.. warning:: + + It is incorrect to pass a timezone directly into the ``datetime.datetime`` constructor (e.g., + ``datetime.datetime(2011, 1, 1, tz=timezone('US/Eastern'))``. Instead, the datetime + needs to be localized using the the localize method on the timezone. + Under the hood, all timestamps are stored in UTC. Scalar values from a ``DatetimeIndex`` with a time zone will have their fields (day, hour, minute) localized to the time zone. However, timestamps with the same UTC value are diff --git a/doc/source/v0.15.0.txt b/doc/source/v0.15.0.txt index 109ed8b286c22..2e3aeaf69957b 100644 --- a/doc/source/v0.15.0.txt +++ b/doc/source/v0.15.0.txt @@ -358,7 +358,9 @@ Bug Fixes - Bug in ``GroupBy.filter()`` where fast path vs. slow path made the filter - return a non scalar value that appeared valid but wasnt' (:issue:`7870`). + return a non scalar value that appeared valid but wasn't (:issue:`7870`). +- Bug in ``date_range()``/``DatetimeIndex()`` when the timezone was inferred from input dates yet incorrect + times were returned when crossing DST boundaries (:issue:`7835`, :issue:`7901`). diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index 5f7c93d38653a..80f9e6cd8db7a 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -416,7 +416,7 @@ def _generate(cls, start, end, periods, name, offset, else: - if inferred_tz is None and tz is not None: + if tz is not None: # naive dates if start is not None and start.tz is not None: start = start.replace(tzinfo=None) diff --git a/pandas/tseries/tests/test_daterange.py b/pandas/tseries/tests/test_daterange.py index 81cf34bbc269b..7b0bfa98690e2 100644 --- a/pandas/tseries/tests/test_daterange.py +++ b/pandas/tseries/tests/test_daterange.py @@ -354,25 +354,51 @@ def test_range_bug(self): def test_range_tz_pytz(self): # GH 2906 tm._skip_if_no_pytz() - from pytz import timezone as tz + from pytz import timezone - start = datetime(2011, 1, 1, tzinfo=tz('US/Eastern')) - end = datetime(2011, 1, 3, tzinfo=tz('US/Eastern')) + tz = timezone('US/Eastern') + start = tz.localize(datetime(2011, 1, 1)) + end = tz.localize(datetime(2011, 1, 3)) dr = date_range(start=start, periods=3) - self.assertEqual(dr.tz, tz('US/Eastern')) + self.assertEqual(dr.tz.zone, tz.zone) self.assertEqual(dr[0], start) self.assertEqual(dr[2], end) dr = date_range(end=end, periods=3) - self.assertEqual(dr.tz, tz('US/Eastern')) + self.assertEqual(dr.tz.zone, tz.zone) self.assertEqual(dr[0], start) self.assertEqual(dr[2], end) dr = date_range(start=start, end=end) - self.assertEqual(dr.tz, tz('US/Eastern')) + self.assertEqual(dr.tz.zone, tz.zone) self.assertEqual(dr[0], start) self.assertEqual(dr[2], end) + + def test_range_tz_dst_straddle_pytz(self): + + tm._skip_if_no_pytz() + from pytz import timezone + tz = timezone('US/Eastern') + dates = [(tz.localize(datetime(2014, 3, 6)), + tz.localize(datetime(2014, 3, 12))), + (tz.localize(datetime(2013, 11, 1)), + tz.localize(datetime(2013, 11, 6)))] + for (start, end) in dates: + dr = date_range(start, end, freq='D') + self.assertEqual(dr[0], start) + self.assertEqual(dr[-1], end) + self.assertEqual(np.all(dr.hour==0), True) + + dr = date_range(start, end, freq='D', tz='US/Eastern') + self.assertEqual(dr[0], start) + self.assertEqual(dr[-1], end) + self.assertEqual(np.all(dr.hour==0), True) + + dr = date_range(start.replace(tzinfo=None), end.replace(tzinfo=None), freq='D', tz='US/Eastern') + self.assertEqual(dr[0], start) + self.assertEqual(dr[-1], end) + self.assertEqual(np.all(dr.hour==0), True) def test_range_tz_dateutil(self): # GH 2906