def test_nonexistent_days(timezone: DstTzInfo):
    """Test that invalid dates are skipped."""
    schedule = CalendarIntervalSchedule(task_id='task', timezone=timezone, months=1,
                                        start_date=date(2016, 3, 31))

    now = timezone.localize(datetime(2016, 4, 30))
    expected = timezone.localize(datetime(2016, 5, 31))
    assert schedule.get_next_run_time(now) == expected
def test_missing_time(timezone: DstTzInfo):
    """
    Test that if the designated time does not exist on a day due to a forward DST shift, the day is
    skipped entirely.

    """
    schedule = CalendarIntervalSchedule(task_id='task', timezone=timezone, days=1, hour=2,
                                        minute=30, start_date=date(2016, 3, 27))
    now = timezone.localize(datetime(2016, 3, 27))
    expected = timezone.localize(datetime(2016, 3, 28, 2, 30))
    assert schedule.get_next_run_time(now) == expected
def test_get_next_run_times(schedule: CalendarIntervalSchedule, timezone: DstTzInfo):
    now = timezone.localize(datetime(2021, 7, 31, 5, 17))
    previous_run_time = timezone.localize(datetime(2016, 3, 5, 3, 0, 8))
    run_times = list(schedule.get_run_times(now, previous_run_time))
    assert run_times == [
        timezone.localize(datetime(2017, 9, 24, 3, 0, 8)),
        timezone.localize(datetime(2019, 4, 15, 3, 0, 8)),
        timezone.localize(datetime(2020, 11, 4, 3, 0, 8))
    ]
def test_repeated_time(timezone: DstTzInfo):
    """
    Test that if the designated time is repeated during a day due to a backward DST shift, the task
    is executed twice that day.

    """
    schedule = CalendarIntervalSchedule(task_id='task', timezone=timezone, days=2, hour=2,
                                        minute=30, start_date=date(2016, 10, 30))

    # The first returned datetime should be the on still in DST
    now = timezone.localize(datetime(2016, 10, 30))
    expected = timezone.localize(datetime(2016, 10, 30, 2, 30), is_dst=True)
    assert schedule.get_next_run_time(now) == expected

    # The next one should then be the one w/o DST
    now = timezone.localize(datetime(2016, 10, 30, 2, 40), is_dst=True)
    expected = timezone.localize(datetime(2016, 10, 30, 2, 30), is_dst=False)
    assert schedule.get_next_run_time(now) == expected

    # But if both times have passed, move on to the next interval
    now = timezone.localize(datetime(2016, 10, 30, 2, 40), is_dst=False)
    expected = timezone.localize(datetime(2016, 11, 1, 2, 30))
    assert schedule.get_next_run_time(now) == expected
def test_end_date(schedule: CalendarIntervalSchedule, timezone: DstTzInfo):
    """Test that end_date is respected."""
    now = timezone.localize(datetime(2020, 12, 31))
    assert schedule.get_next_run_time(now) is None
def test_start_date(schedule: CalendarIntervalSchedule, timezone: DstTzInfo):
    """Test that start_date is respected."""
    now = timezone.localize(datetime(2016, 1, 15))
    expected = timezone.localize(datetime(2016, 3, 5, 3, 0, 8))
    assert schedule.get_next_run_time(now) == expected
def schedule(timezone: DstTzInfo):
    return CalendarIntervalSchedule(
        task_id='taskname', id='testschedule', years=1, months=5, weeks=6, days=8,
        start_date=date(2016, 3, 5), end_date=date(2020, 12, 25), hour=3, second=8,
        timezone=timezone, args=[1, 6], kwargs={'argument': 'value'})