Repository: pandas-dev/pandas

Issue:
Holiday.dates always fails with tz-aware input
The conversion from `start_date` to `base_date` on https://github.com/pydata/pandas/blob/master/pandas/tseries/holiday.py#L206 drops tz information, which causes the `DatetimeIndex` constructor to barf if end_date is tz-aware.  Fixed by https://github.com/pydata/pandas/pull/9824.



Discussion:

Resolving patch:
diff --git a/pandas/tseries/holiday.py b/pandas/tseries/holiday.py
--- a/pandas/tseries/holiday.py
+++ b/pandas/tseries/holiday.py
@@ -203,7 +203,10 @@ def dates(self, start_date, end_date, return_name=False):
         end_date = Timestamp(end_date)
 
         year_offset = DateOffset(years=1)
-        base_date = Timestamp(datetime(start_date.year, self.month, self.day))
+        base_date = Timestamp(
+            datetime(start_date.year, self.month, self.day),
+            tz=start_date.tz,
+        )
         dates = DatetimeIndex(start=base_date, end=end_date, freq=year_offset)
         holiday_dates = self._apply_rule(dates)
         if self.days_of_week is not None:


Test patch:
diff --git a/pandas/tseries/tests/test_holiday.py b/pandas/tseries/tests/test_holiday.py
--- a/pandas/tseries/tests/test_holiday.py
+++ b/pandas/tseries/tests/test_holiday.py
@@ -9,6 +9,7 @@
     HolidayCalendarFactory, next_workday, previous_workday,
     before_nearest_workday, EasterMonday, GoodFriday,
     after_nearest_workday, weekend_to_monday)
+from pytz import utc
 import nose
 
 class TestCalendar(tm.TestCase):
@@ -55,87 +56,119 @@ def setUp(self):
         self.start_date = datetime(2011, 1, 1)
         self.end_date   = datetime(2020, 12, 31)
 
+    def check_results(self, holiday, start, end, expected):
+        self.assertEqual(list(holiday.dates(start, end)), expected)
+        # Verify that timezone info is preserved.
+        self.assertEqual(
+            list(
+                holiday.dates(
+                    utc.localize(Timestamp(start)),
+                    utc.localize(Timestamp(end)),
+                )
+            ),
+            [utc.localize(dt) for dt in expected],
+        )
+
     def test_usmemorialday(self):
-        holidays = USMemorialDay.dates(self.start_date,
-                                       self.end_date)
-        holidayList = [
-                       datetime(2011, 5, 30),
-                       datetime(2012, 5, 28),
-                       datetime(2013, 5, 27),
-                       datetime(2014, 5, 26),
-                       datetime(2015, 5, 25),
-                       datetime(2016, 5, 30),
-                       datetime(2017, 5, 29),
-                       datetime(2018, 5, 28),
-                       datetime(2019, 5, 27),
-                       datetime(2020, 5, 25),
-                       ]
-        self.assertEqual(list(holidays), holidayList)
+        self.check_results(
+            holiday=USMemorialDay,
+            start=self.start_date,
+            end=self.end_date,
+            expected=[
+                datetime(2011, 5, 30),
+                datetime(2012, 5, 28),
+                datetime(2013, 5, 27),
+                datetime(2014, 5, 26),
+                datetime(2015, 5, 25),
+                datetime(2016, 5, 30),
+                datetime(2017, 5, 29),
+                datetime(2018, 5, 28),
+                datetime(2019, 5, 27),
+                datetime(2020, 5, 25),
+            ],
+        )
 
     def test_non_observed_holiday(self):
-        july_3rd = Holiday('July 4th Eve', month=7,  day=3)
-        result = july_3rd.dates("2001-01-01", "2003-03-03")
-        expected = [Timestamp('2001-07-03 00:00:00'),
-                    Timestamp('2002-07-03 00:00:00')]
-        self.assertEqual(list(result), expected)
-        july_3rd = Holiday('July 4th Eve', month=7,  day=3, 
-                           days_of_week=(0, 1, 2, 3))
-        result = july_3rd.dates("2001-01-01", "2008-03-03")
-        expected = [Timestamp('2001-07-03 00:00:00'),
-                    Timestamp('2002-07-03 00:00:00'),
-                    Timestamp('2003-07-03 00:00:00'),
-                    Timestamp('2006-07-03 00:00:00'),
-                    Timestamp('2007-07-03 00:00:00')]
-        self.assertEqual(list(result), expected)
+
+        self.check_results(
+            Holiday('July 4th Eve', month=7, day=3),
+            start="2001-01-01",
+            end="2003-03-03",
+            expected=[
+                Timestamp('2001-07-03 00:00:00'),
+                Timestamp('2002-07-03 00:00:00')
+            ]
+        )
+
+        self.check_results(
+            Holiday('July 4th Eve', month=7, day=3, days_of_week=(0, 1, 2, 3)),
+            start="2001-01-01",
+            end="2008-03-03",
+            expected=[
+                Timestamp('2001-07-03 00:00:00'),
+                Timestamp('2002-07-03 00:00:00'),
+                Timestamp('2003-07-03 00:00:00'),
+                Timestamp('2006-07-03 00:00:00'),
+                Timestamp('2007-07-03 00:00:00'),
+            ]
+        )
 
     def test_easter(self):
-        holidays = EasterMonday.dates(self.start_date,
-                                      self.end_date)
-        holidayList = [Timestamp('2011-04-25 00:00:00'),
-                       Timestamp('2012-04-09 00:00:00'),
-                       Timestamp('2013-04-01 00:00:00'),
-                       Timestamp('2014-04-21 00:00:00'),
-                       Timestamp('2015-04-06 00:00:00'),
-                       Timestamp('2016-03-28 00:00:00'),
-                       Timestamp('2017-04-17 00:00:00'),
-                       Timestamp('2018-04-02 00:00:00'),
-                       Timestamp('2019-04-22 00:00:00'),
-                       Timestamp('2020-04-13 00:00:00')]
-
-
-        self.assertEqual(list(holidays), holidayList)
-        holidays = GoodFriday.dates(self.start_date,
-                                    self.end_date)
-        holidayList = [Timestamp('2011-04-22 00:00:00'),
-                       Timestamp('2012-04-06 00:00:00'),
-                       Timestamp('2013-03-29 00:00:00'),
-                       Timestamp('2014-04-18 00:00:00'),
-                       Timestamp('2015-04-03 00:00:00'),
-                       Timestamp('2016-03-25 00:00:00'),
-                       Timestamp('2017-04-14 00:00:00'),
-                       Timestamp('2018-03-30 00:00:00'),
-                       Timestamp('2019-04-19 00:00:00'),
-                       Timestamp('2020-04-10 00:00:00')]
-        self.assertEqual(list(holidays), holidayList)
-        
+
+        self.check_results(
+            EasterMonday,
+            start=self.start_date,
+            end=self.end_date,
+            expected=[
+                Timestamp('2011-04-25 00:00:00'),
+                Timestamp('2012-04-09 00:00:00'),
+                Timestamp('2013-04-01 00:00:00'),
+                Timestamp('2014-04-21 00:00:00'),
+                Timestamp('2015-04-06 00:00:00'),
+                Timestamp('2016-03-28 00:00:00'),
+                Timestamp('2017-04-17 00:00:00'),
+                Timestamp('2018-04-02 00:00:00'),
+                Timestamp('2019-04-22 00:00:00'),
+                Timestamp('2020-04-13 00:00:00'),
+            ],
+        )
+        self.check_results(
+            GoodFriday,
+            start=self.start_date,
+            end=self.end_date,
+            expected=[
+                Timestamp('2011-04-22 00:00:00'),
+                Timestamp('2012-04-06 00:00:00'),
+                Timestamp('2013-03-29 00:00:00'),
+                Timestamp('2014-04-18 00:00:00'),
+                Timestamp('2015-04-03 00:00:00'),
+                Timestamp('2016-03-25 00:00:00'),
+                Timestamp('2017-04-14 00:00:00'),
+                Timestamp('2018-03-30 00:00:00'),
+                Timestamp('2019-04-19 00:00:00'),
+                Timestamp('2020-04-10 00:00:00'),
+            ],
+        )
 
     def test_usthanksgivingday(self):
-        holidays = USThanksgivingDay.dates(self.start_date,
-                                           self.end_date)
-        holidayList = [
-                       datetime(2011, 11, 24),
-                       datetime(2012, 11, 22),
-                       datetime(2013, 11, 28),
-                       datetime(2014, 11, 27),
-                       datetime(2015, 11, 26),
-                       datetime(2016, 11, 24),
-                       datetime(2017, 11, 23),
-                       datetime(2018, 11, 22),
-                       datetime(2019, 11, 28),
-                       datetime(2020, 11, 26),
-                       ]
-
-        self.assertEqual(list(holidays), holidayList)
+
+        self.check_results(
+            USThanksgivingDay,
+            start=self.start_date,
+            end=self.end_date,
+            expected=[
+                datetime(2011, 11, 24),
+                datetime(2012, 11, 22),
+                datetime(2013, 11, 28),
+                datetime(2014, 11, 27),
+                datetime(2015, 11, 26),
+                datetime(2016, 11, 24),
+                datetime(2017, 11, 23),
+                datetime(2018, 11, 22),
+                datetime(2019, 11, 28),
+                datetime(2020, 11, 26),
+            ],
+        )
 
     def test_argument_types(self):
         holidays = USThanksgivingDay.dates(self.start_date,