Repository: pandas-dev/pandas

Issue:
BUG: using .dt.tz_localize('UTC') returns a tz-unaware object
```
In [48]: s
Out[48]: 
0    1411161507178
1    1411138436009
2    1411123732180
3    1411167606146
4    1411124780140
5    1411159331327
6    1411131745474
7    1411151831454
8    1411152487758
9    1411137160544
Name: 1, dtype: int64

In [49]: pd.DatetimeIndex(pd.to_datetime(s,unit='ms')).tz_localize('UTC').tz_convert('US/Eastern')
Out[49]: 
<class 'pandas.tseries.index.DatetimeIndex'>
[2014-09-19 17:18:27.178000-04:00, ..., 2014-09-19 10:32:40.544000-04:00]
Length: 10, Freq: None, Timezone: US/Eastern
```

Which should be equivalent to

```
In [50]: pd.to_datetime(s,unit='ms').dt.tz_localize('UTC').dt.tz_convert('US/Eastern')
TypeError: Cannot convert tz-naive timestamps, use tz_localize to localize
```



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -26,7 +26,7 @@
 from pandas.core.common import (isnull, notnull, PandasError, _try_sort,
                                 _default_index, _maybe_upcast, _is_sequence,
                                 _infer_dtype_from_scalar, _values_from_object,
-                                is_list_like, _get_dtype)
+                                is_list_like, _get_dtype, _maybe_box_datetimelike)
 from pandas.core.generic import NDFrame, _shared_docs
 from pandas.core.index import Index, MultiIndex, _ensure_index
 from pandas.core.indexing import (_maybe_droplevels,
@@ -1539,7 +1539,7 @@ def get_value(self, index, col, takeable=False):
 
         if takeable:
             series = self._iget_item_cache(col)
-            return series.values[index]
+            return _maybe_box_datetimelike(series.values[index])
 
         series = self._get_item_cache(col)
         engine = self.index._engine
diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py
--- a/pandas/tseries/index.py
+++ b/pandas/tseries/index.py
@@ -744,7 +744,7 @@ def _to_embed(self, keep_tz=False):
 
         This is for internal compat
         """
-        if keep_tz and self.tz is not None and str(self.tz) != 'UTC':
+        if keep_tz and self.tz is not None:
             return self.asobject.values
         return self.values
 


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -3528,7 +3528,7 @@ def test_column_dups_indexing2(self):
 
         # GH 8363
         # datetime ops with a non-unique index
-        df = DataFrame({'A' : np.arange(5,dtype='int64'), 
+        df = DataFrame({'A' : np.arange(5,dtype='int64'),
                         'B' : np.arange(1,6,dtype='int64')},
                        index=[2,2,3,3,4])
         result = df.B-df.A
@@ -3654,6 +3654,18 @@ def test_constructor_with_datetimes(self):
         self.assertEqual(df.iat[0,0],dt)
         assert_series_equal(df.dtypes,Series({'End Date' : np.dtype('object') }))
 
+        # tz-aware (UTC and other tz's)
+        # GH 8411
+        dr = date_range('20130101',periods=3)
+        df = DataFrame({ 'value' : dr})
+        self.assertTrue(df.iat[0,0].tz is None)
+        dr = date_range('20130101',periods=3,tz='UTC')
+        df = DataFrame({ 'value' : dr})
+        self.assertTrue(str(df.iat[0,0].tz) == 'UTC')
+        dr = date_range('20130101',periods=3,tz='US/Eastern')
+        df = DataFrame({ 'value' : dr})
+        self.assertTrue(str(df.iat[0,0].tz) == 'US/Eastern')
+
         # GH 7822
         # preserver an index with a tz on dict construction
         i = date_range('1/1/2011', periods=5, freq='10s', tz = 'US/Eastern')
@@ -7654,7 +7666,7 @@ def test_fillna_dataframe(self):
                              index = list('VWXYZ'))
 
         assert_frame_equal(result, expected)
-        
+
     def test_fillna_columns(self):
         df = DataFrame(np.random.randn(10, 10))
         df.values[:, ::2] = np.nan
@@ -12791,8 +12803,8 @@ def test_consolidate_datetime64(self):
         df.starting = ser_starting.index
         df.ending = ser_ending.index
 
-        assert_array_equal(df.starting.values, ser_starting.index.values)
-        assert_array_equal(df.ending.values, ser_ending.index.values)
+        tm.assert_index_equal(pd.DatetimeIndex(df.starting), ser_starting.index)
+        tm.assert_index_equal(pd.DatetimeIndex(df.ending), ser_ending.index)
 
     def _check_bool_op(self, name, alternative, frame=None, has_skipna=True,
                        has_bool_only=False):
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
@@ -135,6 +135,11 @@ def compare(s, name):
             freq_result = s.dt.freq
             self.assertEqual(freq_result, DatetimeIndex(s.values, freq='infer').freq)
 
+            # let's localize, then convert
+            result = s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')
+            expected = Series(DatetimeIndex(s.values).tz_localize('UTC').tz_convert('US/Eastern'),index=s.index)
+            tm.assert_series_equal(result, expected)
+
         # timedeltaindex
         for s in [Series(timedelta_range('1 day',periods=5)),
                   Series(timedelta_range('1 day 01:23:45',periods=5,freq='s')),
@@ -810,6 +815,15 @@ def test_constructor_dtype_datetime64(self):
         s = Series([pd.NaT, np.nan, '2013-08-05 15:30:00.000001'])
         self.assertEqual(s.dtype,'datetime64[ns]')
 
+        # tz-aware (UTC and other tz's)
+        # GH 8411
+        dr = date_range('20130101',periods=3)
+        self.assertTrue(Series(dr).iloc[0].tz is None)
+        dr = date_range('20130101',periods=3,tz='UTC')
+        self.assertTrue(str(Series(dr).iloc[0].tz) == 'UTC')
+        dr = date_range('20130101',periods=3,tz='US/Eastern')
+        self.assertTrue(str(Series(dr).iloc[0].tz) == 'US/Eastern')
+
     def test_constructor_periodindex(self):
         # GH7932
         # converting a PeriodIndex when put in a Series