Repository: pandas-dev/pandas

Issue:
BUG: date_range(str, tz=str) and date_range(Timestamp) handle tz discontinuity differently
xref #7825
xref (addtl test cases) #7901 

I believe `Out[2]` is correct and `Out[3]` is a bug, and that others will agree with me.
I believe `Out[4]` is a bug, `Out[7]` is correct and `Out[10]` is a bug, but that I will have to do some work to convince others to agree with me.

``` python

In [1]: import pandas as pd

In [2]: list(pd.date_range('2013-11-1', tz='America/Chicago', periods=7, freq='D'))
Out[2]: 
[Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-02 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-03 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-04 00:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-05 00:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-06 00:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-07 00:00:00-0600', tz='America/Chicago', offset='D')]

In [3]: list(pd.date_range(pd.Timestamp('2013-11-1', tz='America/Chicago'), periods=7, freq='D'))
Out[3]: 
[Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-02 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-03 00:00:00-0500', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-03 23:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-04 23:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-05 23:00:00-0600', tz='America/Chicago', offset='D'),
 Timestamp('2013-11-06 23:00:00-0600', tz='America/Chicago', offset='D')]

In [4]: list(pd.date_range('2013-11-1', tz='America/Chicago', periods=7, freq='24H'))
Out[4]: 
[Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-02 00:00:00-0500', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-03 00:00:00-0500', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-04 00:00:00-0600', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-05 00:00:00-0600', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-06 00:00:00-0600', tz='America/Chicago', offset='24H'),
 Timestamp('2013-11-07 00:00:00-0600', tz='America/Chicago', offset='24H')]

In [5]: out = [pd.Timestamp('2013-11-1', tz='America/Chicago')]

In [6]: for i in range(6):
   ...:     out.append(out[-1] + pd.offsets.Hour(24))
   ...:      

In [7]: out
Out[7]: 
[Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-02 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-03 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-03 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-04 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-05 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-06 23:00:00-0600', tz='America/Chicago')]

In [8]: out = [pd.Timestamp('2013-11-1', tz='America/Chicago')]

In [9]: for i in range(6):
   ...:     out.append(out[-1] + pd.offsets.Day(1))
   ...:      

In [10]: out
Out[10]: 
[Timestamp('2013-11-01 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-02 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-03 00:00:00-0500', tz='America/Chicago'),
 Timestamp('2013-11-03 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-04 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-05 23:00:00-0600', tz='America/Chicago'),
 Timestamp('2013-11-06 23:00:00-0600', tz='America/Chicago')]
```



Discussion:

Resolving patch:
diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py
--- 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)


Test patch:
diff --git a/pandas/tseries/tests/test_daterange.py b/pandas/tseries/tests/test_daterange.py
--- 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