from datetime import date
from datetime import datetime
from unittest import TestCase

import dateutil.relativedelta as rd
import pandas

from . import GenericCalendarTest
from ..core import Calendar, LunarCalendar, WesternCalendar
from ..core import Holiday
from ..core import IslamicMixin, JalaliMixin, ChristianMixin
from ..core import MON, TUE, THU, FRI, WED, SAT, SUN
from ..exceptions import UnsupportedDateType


class CalendarTest(GenericCalendarTest):

    def test_private_variables(self):
        self.assertTrue(hasattr(self.cal, '_holidays'))
        private_holidays = self.cal._holidays
        self.assertTrue(isinstance(private_holidays, dict))
        self.cal.holidays(2011)
        self.cal.holidays(2012)
        private_holidays = self.cal._holidays
        self.assertTrue(isinstance(private_holidays, dict))
        self.assertIn(2011, self.cal._holidays)
        self.assertIn(2012, self.cal._holidays)

    def test_year(self):
        holidays = self.cal.holidays()
        self.assertTrue(isinstance(holidays, (tuple, list)))
        self.assertEquals(self.cal._holidays[self.year], holidays)

    def test_another_year(self):
        holidays = self.cal.holidays(2011)
        self.assertTrue(isinstance(holidays, (tuple, list)))
        self.assertEquals(self.cal._holidays[2011], holidays)

    def test_is_working_day(self):
        self.assertRaises(
            NotImplementedError,
            self.cal.is_working_day, date(2012, 1, 1))

    def test_nth_weekday(self):
        # first monday in january 2013
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 1, MON),
            date(2013, 1, 7)
        )
        # second monday in january 2013
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 1, MON, 2),
            date(2013, 1, 14)
        )
        # let's test the limits
        # Jan 1st is a TUE
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 1, TUE),
            date(2013, 1, 1)
        )
        # There's no 6th MONday
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 1, MON, 6),
            None
        )

    def test_nth_weekday_start(self):
        # first thursday after 18th april
        start = date(2013, 4, 18)
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 4, THU, start=start),
            date(2013, 4, 18)
        )
        # first friday after 18th april
        start = date(2013, 4, 18)
        self.assertEquals(
            Calendar.get_nth_weekday_in_month(2013, 4, FRI, start=start),
            date(2013, 4, 19)
        )

    def test_last_weekday(self):
        # last monday in january 2013
        self.assertEquals(
            Calendar.get_last_weekday_in_month(2013, 1, MON),
            date(2013, 1, 28)
        )
        # last thursday
        self.assertEquals(
            Calendar.get_last_weekday_in_month(2013, 1, THU),
            date(2013, 1, 31)
        )

    def test_get_next_weekday_after(self):
        # the first monday after Apr 1 2015
        self.assertEquals(
            Calendar.get_first_weekday_after(date(2015, 4, 1), MON),
            date(2015, 4, 6)
        )

        # the first tuesday after Apr 14 2015
        self.assertEquals(
            Calendar.get_first_weekday_after(date(2015, 4, 14), TUE),
            date(2015, 4, 14)
        )


class LunarCalendarTest(GenericCalendarTest):
    cal_class = LunarCalendar

    def test_new_year(self):
        self.assertEquals(
            self.cal.lunar(2014, 1, 1),
            date(2014, 1, 31)
        )


class MockCalendar(Calendar):

    def holidays(self, year=None):
        return (
            Holiday(date(year, 12, 25), 'Christmas'),
            Holiday(date(year, 1, 1), 'New year'),
        )

    def get_weekend_days(self):
        return []  # no week-end, yes, it's sad


class MockCalendarTest(GenericCalendarTest):
    cal_class = MockCalendar

    def test_holidays_set(self):
        self.assertIn(
            date(self.year, 12, 25), self.cal.holidays_set(self.year))

        self.assertIn(
            date(self.year, 1, 1), self.cal.holidays_set(self.year))

    def test_sorted_dates(self):
        holidays = list(self.cal.holidays(self.year))
        day, label = holidays.pop()
        for next_day, label in holidays:
            self.assertTrue(day <= next_day)
            day = next_day

    def test_add_workingdays_simple(self):
        # day is out of non-working-day
        self.assertEquals(
            self.cal.add_working_days(date(self.year, 12, 20), 0),
            date(self.year, 12, 20)
        )
        self.assertEquals(
            self.cal.add_working_days(date(self.year, 12, 20), 1),
            date(self.year, 12, 21)
        )

    def test_add_workingdays_on_holiday(self):
        # day is in holidays
        self.assertEquals(
            self.cal.add_working_days(date(self.year, 12, 25), 0),
            date(self.year, 12, 25)
        )
        self.assertEquals(
            self.cal.add_working_days(date(self.year, 12, 24), 1),
            date(self.year, 12, 26)
        )
        self.assertEquals(
            self.cal.add_working_days(date(self.year, 12, 24), 2),
            date(self.year, 12, 27)
        )

    def test_add_workingdays_span(self):
        day = date(self.year, 12, 20)
        # since this calendar has no weekends, we'll just have a 2-day-shift
        self.assertEquals(
            self.cal.add_working_days(day, 20),
            date(self.year + 1, 1, 11)
        )

    def test_add_working_days_exceptions(self):
        day = date(self.year, 12, 20)
        christmas = date(self.year, 12, 25)
        boxing = date(self.year, 12, 26)
        # exceptional workday
        self.assertEquals(
            self.cal.add_working_days(day, 20, extra_working_days=[christmas]),
            date(self.year + 1, 1, 10)
        )
        # exceptional holiday + exceptional workday
        self.assertEquals(
            self.cal.add_working_days(day, 20,
                                      extra_working_days=[christmas],
                                      extra_holidays=[boxing]),
            date(self.year + 1, 1, 11)
        )

    def test_add_exceptions(self):
        december_20th = date(self.year, 12, 20)
        christmas = date(self.year, 12, 25)
        # target_working_day *is* a working day
        target_working_day = self.cal.add_working_days(december_20th, 1)
        # Add extra working days
        extra_working_days = [christmas]
        # add extra holidays
        extra_holidays = [target_working_day]
        self.assertFalse(self.cal.is_working_day(christmas))
        self.assertTrue(
            self.cal.is_working_day(christmas,
                                    extra_working_days=extra_working_days))

        self.assertTrue(self.cal.is_working_day(target_working_day))
        self.assertFalse(
            self.cal.is_working_day(target_working_day,
                                    extra_holidays=extra_holidays))
        # test is_holiday
        self.assertTrue(self.cal.is_holiday(christmas))

    def test_get_holiday_label(self):
        self.assertEqual(
            self.cal.get_holiday_label(date(2014, 1, 1)), 'New year')
        self.assertIsNone(
            self.cal.get_holiday_label(date(2014, 1, 2)))

    def test_add_working_days_backwards(self):
        day = date(self.year, 1, 3)
        # since this calendar has no weekends, we'll just have a 1-day-shift
        self.assertEquals(
            self.cal.add_working_days(day, -7),
            date(self.year - 1, 12, 26)
        )
        self.assertEquals(
            self.cal.sub_working_days(day, 7),
            date(self.year - 1, 12, 26)
        )
        # Negative argument to sub_working_days -> converted to positive.
        self.assertEquals(
            self.cal.sub_working_days(day, -7),
            date(self.year - 1, 12, 26)
        )


class SimpleObservanceCalendar(Calendar):
    """
    A simple calendar with a couple of holidays with typical observance rules:
    If a holiday falls on a weekend, then its observance is shifted to a
    nearby weekday.
    """
    FIXED_HOLIDAYS = (
        Holiday(
            date(2000, 12, 24), 'Christmas Eve', indication='December 24th',
            observance_shift=dict(weekday=rd.FR(-1)),
        ),
        Holiday(date(2000, 12, 25), 'Christmas', indication='December 25th'),
    )

    def get_weekend_days(self):
        return SAT, SUN


class ObservanceCalendarTest(GenericCalendarTest):
    """
    A simple calendar with days shifted for observance.
    """
    cal_class = SimpleObservanceCalendar

    def test_observance(self):
        """
        Each Holiday returned by the calendar should be aware of its indicated
        date and observance date.
        """
        holidays = list(self.cal.holidays(2011))
        assert len(holidays) == 2
        xmas_eve, xmas_day = holidays
        assert xmas_eve == date(2011, 12, 24)
        assert self.cal.get_observed_date(xmas_eve) == date(2011, 12, 23)
        assert xmas_day == date(2011, 12, 25)
        assert self.cal.get_observed_date(xmas_day) == date(2011, 12, 26)


class IslamicMixinTest(GenericCalendarTest):
    cal_class = IslamicMixin

    def test_year_conversion(self):
        days = self.cal.converted(2013)
        self.assertEquals(len(days), 365)


class JalaliMixinTest(GenericCalendarTest):
    cal_class = JalaliMixin

    def test_year_conversion(self):
        days = self.cal.converted(2013)
        self.assertEquals(len(days), 365)


class MockChristianCalendar(WesternCalendar, ChristianMixin):
    pass


class MockChristianCalendarTest(GenericCalendarTest):
    cal_class = MockChristianCalendar

    def test_year_2014(self):
        holidays = self.cal.holidays_set(2014)
        self.assertNotIn(date(2014, 1, 6), holidays)  # Epiphany
        self.assertNotIn(date(2014, 3, 3), holidays)  # Clean Monday
        self.assertNotIn(date(2014, 3, 5), holidays)  # Ash Wednesday
        self.assertNotIn(date(2014, 3, 25), holidays)  # Annunciation
        self.assertNotIn(date(2014, 4, 17), holidays)  # Holy Thursday
        self.assertNotIn(date(2014, 4, 18), holidays)  # 'Good Friday
        self.assertNotIn(date(2014, 4, 19), holidays)  # Easter sat
        self.assertNotIn(date(2014, 4, 20), holidays)  # Easter Sun
        self.assertNotIn(date(2014, 4, 21), holidays)  # Easter Mon
        self.assertNotIn(date(2014, 5, 29), holidays)  # Ascension
        self.assertNotIn(date(2014, 6, 8), holidays)   # Whit Sunday
        self.assertNotIn(date(2014, 6, 9), holidays)   # Whit Monday
        self.assertNotIn(date(2014, 6, 19), holidays)  # Corp. Christi
        self.assertNotIn(date(2014, 8, 15), holidays)  # Assumption
        self.assertNotIn(date(2014, 11, 1), holidays)  # All Saints
        self.assertNotIn(date(2014, 12, 8), holidays)  # Imm. Conc.
        self.assertNotIn(date(2014, 12, 24), holidays)  # Xmas Eve
        self.assertNotIn(date(2014, 12, 26), holidays)  # Boxing Day

        # The only Christian day that is a holiday for every calendar
        self.assertIn(date(2014, 12, 25), holidays)  # XMas

        # Only 2 days: Jan 1st and Christmas
        self.assertEquals(len(holidays), 2)


class NoWeekendCalendar(Calendar):
    """
    This calendar class has no WEEKEND_DAYS and no `get_weekend_days()` method.
    It has to fail when trying to fetch its weekend days / holidays
    """


class NoWeekendCalendarTest(GenericCalendarTest):
    cal_class = NoWeekendCalendar

    def test_weekend(self):
        day = date(2017, 5, 13)  # This is a Saturday
        with self.assertRaises(NotImplementedError):
            self.cal.is_working_day(day)
        day = date(2017, 5, 17)  # This is a Wednesday
        with self.assertRaises(NotImplementedError):
            self.cal.is_working_day(day)


class WeekendOnWednesdayCalendar(Calendar):
    """
    This calendar class weekend days is on Wednesday and we don't overwrite
    the `get_weekend_days()` method. It should be fine.
    """
    WEEKEND_DAYS = (WED,)


class WeekendOnWednesdayCalendarTest(GenericCalendarTest):
    cal_class = WeekendOnWednesdayCalendar

    def test_weekend(self):
        day = date(2017, 5, 13)  # This is a Saturday
        self.assertTrue(self.cal.is_working_day(day))
        day = date(2017, 5, 17)  # This is a Wednesday
        self.assertFalse(self.cal.is_working_day(day))


class OverwriteGetWeekendDaysCalendar(Calendar):
    """
    This calendar class has no WEEKEND_DAYS and we overwrite
    its `get_weekend_days` method.
    Should work.
    """
    def get_weekend_days(self):
        return (WED,)


class OverwriteGetWeekendDaysCalendarTest(GenericCalendarTest):
    cal_class = OverwriteGetWeekendDaysCalendar

    def test_weekend(self):
        day = date(2017, 5, 13)  # This is a Saturday
        self.assertTrue(self.cal.is_working_day(day))
        day = date(2017, 5, 17)  # This is a Wednesday
        self.assertFalse(self.cal.is_working_day(day))


class NoHolidayCalendar(Calendar):
    WEEKEND_DAYS = (SAT, SUN)


class WorkingDaysDeltatest(TestCase):

    def test_zero(self):
        days = (
            date(2018, 12, 21),  # a Thursday
            date(2018, 12, 23),  # a Sunday
            date(2018, 12, 25),  # a holiday in Christian calendars
        )
        for day in days:
            cal = NoHolidayCalendar()
            self.assertEqual(cal.get_working_days_delta(day, day), 0)
            cal = MockChristianCalendar()
            self.assertEqual(cal.get_working_days_delta(day, day), 0)

    def test_no_holidays_simple(self):
        cal = NoHolidayCalendar()
        day1 = date(2018, 12, 21)
        day2 = date(2018, 12, 26)
        delta = cal.get_working_days_delta(day1, day2)
        # there are 3 days, because of the week-ends
        self.assertEqual(delta, 3)

        # No difference if you swap the two dates
        delta = cal.get_working_days_delta(day2, day1)
        self.assertEqual(delta, 3)

    def test_no_holidays_over_2_years(self):
        cal = NoHolidayCalendar()
        day1 = date(2018, 12, 21)
        day2 = date(2019, 1, 4)
        delta = cal.get_working_days_delta(day1, day2)
        # there are 10 days, because of the week-ends
        self.assertEqual(delta, 10)

        # No difference if you swap the two dates
        delta = cal.get_working_days_delta(day2, day1)
        self.assertEqual(delta, 10)

    def test_christian_simple(self):
        cal = MockChristianCalendar()
        day1 = date(2018, 12, 21)
        day2 = date(2018, 12, 26)
        delta = cal.get_working_days_delta(day1, day2)
        # there are 2 days, because of the week-end + Christmas Day
        self.assertEqual(delta, 2)

        # No difference if you swap the two dates
        delta = cal.get_working_days_delta(day2, day1)
        self.assertEqual(delta, 2)

    def test_christian_over_2_years(self):
        cal = MockChristianCalendar()
        day1 = date(2018, 12, 21)
        day2 = date(2019, 1, 4)
        delta = cal.get_working_days_delta(day1, day2)
        # there are 8 days, because of the week-ends + Xmas day + New Year
        self.assertEqual(delta, 8)

        # No difference if you swap the two dates
        delta = cal.get_working_days_delta(day2, day1)
        self.assertEqual(delta, 8)

    def test_with_datetimes(self):
        cal = MockChristianCalendar()
        day1 = datetime(2018, 12, 21)
        day2 = date(2018, 12, 26)
        delta = cal.get_working_days_delta(day1, day2)
        # there are 2 days, because of the week-end + Christmas Day
        self.assertEqual(delta, 2)

        # No difference if you swap the two dates
        delta = cal.get_working_days_delta(day2, day1)
        self.assertEqual(delta, 2)

    def test_with_including_first_day(self):
        # linked to #393
        cal = MockChristianCalendar()
        day1 = date(2018, 12, 24)  # December 24th: not holiday so working day
        day2 = date(2018, 12, 25)  # December 25th: Christmas

        # not including the first day, should return 0
        delta = cal.get_working_days_delta(day1, day2)
        self.assertEqual(delta, 0)

        # including the first day, should return 1
        delta = cal.get_working_days_delta(day1, day2, include_start=True)
        self.assertEqual(delta, 1)


class NoDocstring(Calendar):
    pass


class EmptyDocstring(Calendar):
    ""


class OneLineDocstring(Calendar):
    "One line"


class MultipleLineDocstring(Calendar):
    """Multiple line

    docstrings can span over multiple lines.
    """


class MultipleLineEmptyFirstDocstring(Calendar):
    """

    Multiple line empty first

    docstrings can span over multiple lines.
    """


class CalendarClassName(TestCase):
    def test_no_docstring(self):
        self.assertEqual(NoDocstring.name, "NoDocstring")

    def test_empty_docstring(self):
        self.assertEqual(EmptyDocstring.name, "EmptyDocstring")

    def test_oneline_docstring(self):
        self.assertEqual(OneLineDocstring.name, "One line")

    def test_multiple_line_docstring(self):
        self.assertEqual(MultipleLineDocstring.name, "Multiple line")

    def test_multiple_line_empty_first_docstring(self):
        self.assertEqual(
            MultipleLineEmptyFirstDocstring.name, "Multiple line empty first"
        )


class TestAcceptableDateTypes(GenericCalendarTest):
    """
    Test cases about accepted date and datetime types.
    """
    cal_class = MockCalendar
    unsupported = ('hello', 1)

    def test_unsupported_type_is_working_day(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.is_working_day(arg)

        # Extra holidays optional argument
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.is_working_day(
                    date(2018, 1, 1),
                    extra_holidays=[arg]
                )
        # Extra working days optional argument
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.is_working_day(
                    date(2018, 1, 1),
                    extra_working_days=[arg]
                )

    def test_unsupported_type_is_holiday(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.is_holiday(arg)

        # Extra holidays optional argument
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.is_holiday(
                    date(2018, 1, 1),
                    extra_holidays=[arg]
                )

    def test_unsupported_type_holiday_label(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.get_holiday_label(arg)

    def test_unsupported_type_add_sub_working_days(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.add_working_days(arg, 1)

        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.sub_working_days(arg, 1)

        # Extra holidays optional argument
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.add_working_days(
                    date(2018, 1, 1), 1,
                    extra_holidays=[arg]
                )
        # Extra working days optional argument
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.add_working_days(
                    date(2018, 1, 1), 1,
                    extra_working_days=[arg]
                )
        # NOTE: no need to test "sub", they're calling each other.

    def test_unsupported_type_find_following_working_day(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.find_following_working_day(arg)

    def test_unsupported_type_get_nth_weekday_in_month(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.get_nth_weekday_in_month(2018, 1, MON, start=arg)

    def test_unsupported_type_get_working_days_delta(self):
        for arg in self.unsupported:
            with self.assertRaises(UnsupportedDateType):
                self.cal.get_working_days_delta(date(2018, 1, 1), arg)

            with self.assertRaises(UnsupportedDateType):
                self.cal.get_working_days_delta(arg, date(2018, 1, 1))

    def test_datetime(self):
        self.assertFalse(
            self.cal.is_working_day(datetime(2014, 1, 1)))
        self.assertTrue(
            self.cal.is_holiday(datetime(2014, 1, 1)))

    def test_add_working_days_datetime(self):
        # datetime inside, date outside
        self.assertEquals(
            self.cal.add_working_days(
                datetime(self.year, 12, 20, 12, 34, 56), 0),
            date(self.year, 12, 20)
        )
        self.assertEquals(
            self.cal.add_working_days(
                datetime(self.year, 12, 20, 12, 34, 56), 1),
            date(self.year, 12, 21)
        )

        # Use the `keep_datetime` option
        self.assertEquals(
            self.cal.add_working_days(
                datetime(self.year, 12, 20, 12, 34, 56),
                0, keep_datetime=True),
            datetime(self.year, 12, 20, 12, 34, 56)
        )
        self.assertEquals(
            self.cal.add_working_days(
                datetime(self.year, 12, 20, 12, 34, 56),
                1, keep_datetime=True),
            datetime(self.year, 12, 21, 12, 34, 56)
        )

    def test_sub_working_days_datetime(self):
        # datetime inside, date outside
        self.assertEquals(
            self.cal.sub_working_days(
                datetime(self.year, 12, 20, 12, 34, 56), 0),
            date(self.year, 12, 20)
        )
        self.assertEquals(
            self.cal.sub_working_days(
                datetime(self.year, 12, 20, 12, 34, 56), 1),
            date(self.year, 12, 19)
        )

        # Use the `keep_datetime` option
        self.assertEquals(
            self.cal.sub_working_days(
                datetime(self.year, 12, 20, 12, 34, 56),
                0, keep_datetime=True),
            datetime(self.year, 12, 20, 12, 34, 56)
        )
        self.assertEquals(
            self.cal.sub_working_days(
                datetime(self.year, 12, 20, 12, 34, 56),
                1, keep_datetime=True),
            datetime(self.year, 12, 19, 12, 34, 56)
        )

    def test_get_holiday_label_with_datetime(self):
        self.assertEqual(
            self.cal.get_holiday_label(datetime(2014, 1, 1)), 'New year')
        self.assertIsNone(
            self.cal.get_holiday_label(datetime(2014, 1, 2)))


class PandasTimestampTest(GenericCalendarTest):
    cal_class = MockCalendar

    def test_panda_type_is_working_day(self):
        self.assertFalse(
            self.cal.is_working_day(pandas.to_datetime("2018-1-1"))
        )

        # Extra holidays optional argument
        self.assertFalse(
            self.cal.is_working_day(
                date(2018, 1, 2),
                extra_holidays=[pandas.to_datetime("2018-1-2")]
            )
        )
        # Extra working days optional argument
        self.assertTrue(
            self.cal.is_working_day(
                date(2018, 1, 1),
                extra_working_days=[pandas.to_datetime("2018-1-1")]
            )
        )

    def test_panda_type_is_holiday(self):
        self.assertTrue(self.cal.is_holiday(pandas.to_datetime("2018-1-1")))

        # Extra holidays optional argument
        self.assertTrue(
            self.cal.is_holiday(
                date(2018, 2, 1),
                extra_holidays=[pandas.to_datetime("2018-2-1")]
            )
        )

    def test_panda_type_holiday_label(self):
        label = self.cal.get_holiday_label(pandas.to_datetime("2018-1-1"))
        self.assertEqual(label, "New year")

    def test_panda_type_add_sub_working_days(self):
        day = pandas.to_datetime("2018-12-24")
        next_day = self.cal.add_working_days(day, 1)
        self.assertEqual(next_day, date(2018, 12, 26))

        previous_day = self.cal.sub_working_days(next_day, 1)
        self.assertEqual(previous_day, date(2018, 12, 24))

        next_day = self.cal.add_working_days(
            date(2018, 12, 24), 1,
            extra_holidays=[pandas.to_datetime("2018-12-26")]
        )
        self.assertEqual(next_day, date(2018, 12, 27))

        next_day = self.cal.add_working_days(
            date(2018, 12, 24), 1,
            extra_working_days=[pandas.to_datetime("2018-12-25")]
        )
        self.assertEqual(next_day, date(2018, 12, 25))

    def test_unsupported_type_find_following_working_day(self):
        following_day = self.cal.find_following_working_day(
            pandas.to_datetime("2018-1-1")
        )
        # No weekend days, the next day is "today"
        self.assertEqual(following_day, date(2018, 1, 1))

    def test_unsupported_type_get_nth_weekday_in_month(self):
        start = pandas.to_datetime("2018-1-4")
        monday = self.cal.get_nth_weekday_in_month(2018, 1, MON, start=start)
        self.assertEqual(monday, date(2018, 1, 8))

    def test_unsupported_type_get_working_days_delta(self):
        start, end = date(2018, 12, 23), pandas.to_datetime("2018-12-26")
        delta = self.cal.get_working_days_delta(start, end)
        self.assertEqual(delta, 2)
        delta = self.cal.get_working_days_delta(end, start)
        self.assertEqual(delta, 2)

        start, end = pandas.to_datetime("2018-12-23"), date(2018, 12, 26)
        delta = self.cal.get_working_days_delta(start, end)
        self.assertEqual(delta, 2)
        delta = self.cal.get_working_days_delta(end, start)
        self.assertEqual(delta, 2)
