Repository: pandas-dev/pandas

Issue:
datetime like series .dt properties fail after ts.dt.tz_localize(tz1).dt.tz_convert(tz2) sequence
Second tz_convert fails with AmbiguousTimeError ('UTC' in the example, but other timezones fail too).

EDIT: Actually it's not only second tz_convert that fails, it looks like most (if not all) of the .dt accessed properties are affected

``` python
t = pd.Series(pd.date_range('2015-01-01', '2016-01-01', freq='T'))
t = t.dt.tz_localize('UTC').dt.tz_convert('America/Chicago')
t.head(10)
```

```
0   2014-12-31 18:00:00-06:00
1   2014-12-31 18:01:00-06:00
2   2014-12-31 18:02:00-06:00
3   2014-12-31 18:03:00-06:00
4   2014-12-31 18:04:00-06:00
5   2014-12-31 18:05:00-06:00
6   2014-12-31 18:06:00-06:00
7   2014-12-31 18:07:00-06:00
8   2014-12-31 18:08:00-06:00
9   2014-12-31 18:09:00-06:00
dtype: datetime64[ns, America/Chicago]
```

``` python
t.dt.tz_convert('UTC')
```

```
---------------------------------------------------------------------------

AmbiguousTimeError                        Traceback (most recent call last)

/usr/lib/python3.5/site-packages/pandas/core/series.py in _make_dt_accessor(self)
   2639         try:
-> 2640             return maybe_to_datetimelike(self)
   2641         except Exception:


/usr/lib/python3.5/site-packages/pandas/tseries/common.py in maybe_to_datetimelike(data, copy)
     48     if is_datetime64_dtype(data.dtype) or is_datetime64tz_dtype(data.dtype):
---> 49         return DatetimeProperties(DatetimeIndex(data, copy=copy, freq='infer'), index, name=data.name)
     50     elif is_timedelta64_dtype(data.dtype):


/usr/lib/python3.5/site-packages/pandas/util/decorators.py in wrapper(*args, **kwargs)
     88                     kwargs[new_arg_name] = new_arg_value
---> 89             return func(*args, **kwargs)
     90         return wrapper


/usr/lib/python3.5/site-packages/pandas/tseries/index.py in __new__(cls, data, freq, start, end, periods, copy, name, tz, verify_integrity, normalize, closed, ambiguous, dtype, **kwargs)
    343                     subarr = tslib.tz_localize_to_utc(ints, tz,
--> 344                                                       ambiguous=ambiguous)
    345 


pandas/tslib.pyx in pandas.tslib.tz_localize_to_utc (pandas/tslib.c:64516)()


AmbiguousTimeError: Cannot infer dst time from Timestamp('2015-11-01 01:00:00'), try using the 'ambiguous' argument


During handling of the above exception, another exception occurred:


AttributeError                            Traceback (most recent call last)

<ipython-input-2-eb75730cd6fc> in <module>()
----> 1 t.dt.tz_convert('UTC')


/usr/lib/python3.5/site-packages/pandas/core/generic.py in __getattr__(self, name)
   2239                 or name in self._metadata
   2240                 or name in self._accessors):
-> 2241             return object.__getattribute__(self, name)
   2242         else:
   2243             if name in self._info_axis:


/usr/lib/python3.5/site-packages/pandas/core/base.py in __get__(self, instance, owner)
    186             # this ensures that Series.str.<method> is well defined
    187             return self.accessor_cls
--> 188         return self.construct_accessor(instance)
    189 
    190     def __set__(self, instance, value):


/usr/lib/python3.5/site-packages/pandas/core/series.py in _make_dt_accessor(self)
   2640             return maybe_to_datetimelike(self)
   2641         except Exception:
-> 2642             raise AttributeError("Can only use .dt accessor with datetimelike "
   2643                                  "values")
   2644 


AttributeError: Can only use .dt accessor with datetimelike values
```

``` python

```



Discussion:
This seems to come down to the failing of `DatetimeIndex(t)` (which is used within the dt accessor):

```
In [37]: t.head()
Out[37]:
0   2014-12-31 18:00:00-06:00
1   2014-12-31 18:01:00-06:00
2   2014-12-31 18:02:00-06:00
3   2014-12-31 18:03:00-06:00
4   2014-12-31 18:04:00-06:00
dtype: datetime64[ns, America/Chicago]

In [38]: pd.DatetimeIndex(t)
---------------------------------------------------------------------------
AmbiguousTimeError                        Traceback (most recent call last)
<ipython-input-38-3e6430dea298> in <module>()
----> 1 pd.DatetimeIndex(t)

c:\users\vdbosscj\scipy\pandas-joris\pandas\util\decorators.pyc in wrapper(*args
, **kwargs)
     87                 else:
     88                     kwargs[new_arg_name] = new_arg_value
---> 89             return func(*args, **kwargs)
     90         return wrapper
     91     return _deprecate_kwarg

c:\users\vdbosscj\scipy\pandas-joris\pandas\tseries\index.pyc in __new__(cls, da
ta, freq, start, end, periods, copy, name, tz, verify_integrity, normalize, clos
ed, ambiguous, dtype, **kwargs)
    342                     ints = subarr.view('i8')
    343                     subarr = tslib.tz_localize_to_utc(ints, tz,
--> 344                                                       ambiguous=ambiguou
s)
    345
    346                 subarr = subarr.view(_NS_DTYPE)

tslib.pyx in pandas.tslib.tz_localize_to_utc (pandas\tslib.c:55271)()

AmbiguousTimeError: Cannot infer dst time from Timestamp('2015-11-01 01:00:00'),
 try using the 'ambiguous' argument
```

When providing tz data to `DatetimeIndex`, it first makes it naive and then converts back to the tz, which fails without supplying `ambiguous='infer'`. 


Resolving patch:
diff --git a/pandas/tseries/common.py b/pandas/tseries/common.py
--- a/pandas/tseries/common.py
+++ b/pandas/tseries/common.py
@@ -45,8 +45,10 @@ def maybe_to_datetimelike(data, copy=False):
         raise TypeError("cannot convert an object of type {0} to a datetimelike index".format(type(data)))
 
     index = data.index
-    if is_datetime64_dtype(data.dtype) or is_datetime64tz_dtype(data.dtype):
+    if is_datetime64_dtype(data.dtype):
         return DatetimeProperties(DatetimeIndex(data, copy=copy, freq='infer'), index, name=data.name)
+    elif is_datetime64tz_dtype(data.dtype):
+        return DatetimeProperties(DatetimeIndex(data, copy=copy, freq='infer', ambiguous='infer'), index, name=data.name)
     elif is_timedelta64_dtype(data.dtype):
         return TimedeltaProperties(TimedeltaIndex(data, copy=copy, freq='infer'), index, name=data.name)
     else:
diff --git a/pandas/tseries/frequencies.py b/pandas/tseries/frequencies.py
--- a/pandas/tseries/frequencies.py
+++ b/pandas/tseries/frequencies.py
@@ -851,10 +851,11 @@ def infer_freq(index, warn=True):
             raise TypeError("cannot infer freq from a non-convertible index type {0}".format(type(index)))
         index = index.values
 
-    try:
-        index = pd.DatetimeIndex(index)
-    except AmbiguousTimeError:
-        index = pd.DatetimeIndex(index.asi8)
+    if not isinstance(index, pd.DatetimeIndex):
+        try:
+            index = pd.DatetimeIndex(index)
+        except AmbiguousTimeError:
+            index = pd.DatetimeIndex(index.asi8)
 
     inferer = _FrequencyInferer(index, warn=warn)
     return inferer.get_freq()
diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py
--- a/pandas/tseries/index.py
+++ b/pandas/tseries/index.py
@@ -194,7 +194,8 @@ def _join_i8_wrapper(joinf, **kwargs):
     _datetimelike_ops = ['year','month','day','hour','minute','second',
                          'weekofyear','week','dayofweek','weekday','dayofyear','quarter', 'days_in_month', 'daysinmonth',
                          'date','time','microsecond','nanosecond','is_month_start','is_month_end',
-                         'is_quarter_start','is_quarter_end','is_year_start','is_year_end','tz','freq']
+                         'is_quarter_start','is_quarter_end','is_year_start','is_year_end',
+                         'tz','freq']
     _is_numeric_dtype = False
 
 
@@ -269,14 +270,7 @@ def __new__(cls, data=None,
                                                      dayfirst=dayfirst,
                                                      yearfirst=yearfirst)
 
-        if is_datetimetz(data):
-            # extract the data whether a Series or Index
-            if isinstance(data, ABCSeries):
-                data = data._values
-            tz = data.tz
-            data = data.tz_localize(None, ambiguous='infer').values
-
-        if issubclass(data.dtype.type, np.datetime64):
+        if issubclass(data.dtype.type, np.datetime64) or is_datetimetz(data):
             if isinstance(data, ABCSeries):
                 data = data._values
             if isinstance(data, DatetimeIndex):


Test patch:
diff --git a/pandas/tests/test_index.py b/pandas/tests/test_index.py
--- a/pandas/tests/test_index.py
+++ b/pandas/tests/test_index.py
@@ -3348,6 +3348,15 @@ def test_construction_with_alt(self):
         i2 = DatetimeIndex(i.tz_localize(None).asi8, dtype=i.dtype, tz=i.dtype.tz)
         self.assert_index_equal(i, i2)
 
+        # localize into the provided tz
+        i2 = DatetimeIndex(i.tz_localize(None).asi8, tz='UTC')
+        expected = i.tz_localize(None).tz_localize('UTC')
+        self.assert_index_equal(i2, expected)
+
+        i2 = DatetimeIndex(i, tz='UTC')
+        expected = i.tz_convert('UTC')
+        self.assert_index_equal(i2, expected)
+
         # incompat tz/dtype
         self.assertRaises(ValueError, lambda : DatetimeIndex(i.tz_localize(None).asi8, dtype=i.dtype, tz='US/Pacific'))
 
diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py
--- a/pandas/tests/test_series.py
+++ b/pandas/tests/test_series.py
@@ -224,6 +224,18 @@ def get_dir(s):
         results = get_dir(s)
         tm.assert_almost_equal(results, list(sorted(set(ok_for_period + ok_for_period_methods))))
 
+        # 11295
+        # ambiguous time error on the conversions
+        s = Series(pd.date_range('2015-01-01', '2016-01-01', freq='T'))
+        s = s.dt.tz_localize('UTC').dt.tz_convert('America/Chicago')
+        results = get_dir(s)
+        tm.assert_almost_equal(results, list(sorted(set(ok_for_dt + ok_for_dt_methods))))
+        expected = Series(pd.date_range('2015-01-01',
+                                        '2016-01-01',
+                                        freq='T',
+                                        tz='UTC').tz_convert('America/Chicago'))
+        tm.assert_series_equal(s, expected)
+
         # no setting allowed
         s = Series(date_range('20130101',periods=5,freq='D'))
         with tm.assertRaisesRegexp(ValueError, "modifications"):