Exemple #1
0
    def remaining_delta(self, last_run_at, tz=None, ffwd=ffwd):
        # pylint: disable=redefined-outer-name
        # caching global ffwd
        tz = tz or self.tz
        last_run_at = self.maybe_make_aware(last_run_at)
        now = self.maybe_make_aware(self.now())
        dow_num = last_run_at.isoweekday() % 7  # Sunday is day 0, not day 7

        execute_this_date = (last_run_at.month in self.month_of_year
                             and last_run_at.day in self.day_of_month
                             and dow_num in self.day_of_week)

        execute_this_hour = (execute_this_date and last_run_at.day == now.day
                             and last_run_at.month == now.month
                             and last_run_at.year == now.year
                             and last_run_at.hour in self.hour
                             and last_run_at.minute < max(self.minute))

        if execute_this_hour:
            next_minute = min(minute for minute in self.minute
                              if minute > last_run_at.minute)
            delta = ffwd(minute=next_minute, second=0, microsecond=0)
        else:
            next_minute = min(self.minute)
            execute_today = (execute_this_date
                             and last_run_at.hour < max(self.hour))

            if execute_today:
                next_hour = min(hour for hour in self.hour
                                if hour > last_run_at.hour)
                delta = ffwd(hour=next_hour,
                             minute=next_minute,
                             second=0,
                             microsecond=0)
            else:
                next_hour = min(self.hour)
                all_dom_moy = (self._orig_day_of_month == '*'
                               and self._orig_month_of_year == '*')
                if all_dom_moy:
                    next_day = min(
                        [day for day in self.day_of_week if day > dow_num]
                        or self.day_of_week)
                    add_week = next_day == dow_num

                    delta = ffwd(
                        weeks=add_week and 1 or 0,
                        weekday=(next_day - 1) % 7,
                        hour=next_hour,
                        minute=next_minute,
                        second=0,
                        microsecond=0,
                    )
                else:
                    delta = self._delta_to_next(last_run_at, next_hour,
                                                next_minute)
        return self.to_local(last_run_at), delta, self.to_local(now)
Exemple #2
0
def test_remaining():
    # Relative
    remaining(datetime.utcnow(), timedelta(hours=1), relative=True)
    """
    The upcoming cases check whether the next run is calculated correctly
    """
    eastern_tz = pytz.timezone("US/Eastern")
    tokyo_tz = pytz.timezone("Asia/Tokyo")

    # Case 1: `start` in UTC and `now` in other timezone
    start = datetime.now(pytz.utc)
    now = datetime.now(eastern_tz)
    delta = timedelta(hours=1)
    assert str(start.tzinfo) == str(pytz.utc)
    assert str(now.tzinfo) == str(eastern_tz)
    rem_secs = remaining(start, delta, now).total_seconds()
    # assert remaining time is approximately equal to delta
    assert rem_secs == pytest.approx(delta.total_seconds(), abs=1)

    # Case 2: `start` and `now` in different timezones (other than UTC)
    start = datetime.now(eastern_tz)
    now = datetime.now(tokyo_tz)
    delta = timedelta(hours=1)
    assert str(start.tzinfo) == str(eastern_tz)
    assert str(now.tzinfo) == str(tokyo_tz)
    rem_secs = remaining(start, delta, now).total_seconds()
    assert rem_secs == pytest.approx(delta.total_seconds(), abs=1)
    """
    Case 3: DST check
    Suppose start (which is last_run_time) is in EST while next_run is in EDT,
    then check whether the `next_run` is actually the time specified in the
    start (i.e. there is not an hour diff due to DST).
    In 2019, DST starts on March 10
    """
    start = eastern_tz.localize(
        datetime(month=3, day=9, year=2019, hour=10, minute=0))  # EST
    now = eastern_tz.localize(
        datetime(day=11, month=3, year=2019, hour=1, minute=0))  # EDT
    delta = ffwd(hour=10,
                 year=2019,
                 microsecond=0,
                 minute=0,
                 second=0,
                 day=11,
                 weeks=0,
                 month=3)
    # `next_actual_time` is the next time to run (derived from delta)
    next_actual_time = eastern_tz.localize(
        datetime(day=11, month=3, year=2019, hour=10, minute=0))  # EDT
    assert start.tzname() == "EST"
    assert now.tzname() == "EDT"
    assert next_actual_time.tzname() == "EDT"
    rem_time = remaining(start, delta, now)
    next_run = now + rem_time
    assert next_run == next_actual_time
Exemple #3
0
def test_remaining():
    # Relative
    remaining(datetime.utcnow(), timedelta(hours=1), relative=True)

    """
    The upcoming cases check whether the next run is calculated correctly
    """
    eastern_tz = pytz.timezone("US/Eastern")
    tokyo_tz = pytz.timezone("Asia/Tokyo")

    # Case 1: `start` in UTC and `now` in other timezone
    start = datetime.now(pytz.utc)
    now = datetime.now(eastern_tz)
    delta = timedelta(hours=1)
    assert str(start.tzinfo) == str(pytz.utc)
    assert str(now.tzinfo) == str(eastern_tz)
    rem_secs = remaining(start, delta, now).total_seconds()
    # assert remaining time is approximately equal to delta
    assert rem_secs == pytest.approx(delta.total_seconds(), abs=1)

    # Case 2: `start` and `now` in different timezones (other than UTC)
    start = datetime.now(eastern_tz)
    now = datetime.now(tokyo_tz)
    delta = timedelta(hours=1)
    assert str(start.tzinfo) == str(eastern_tz)
    assert str(now.tzinfo) == str(tokyo_tz)
    rem_secs = remaining(start, delta, now).total_seconds()
    assert rem_secs == pytest.approx(delta.total_seconds(), abs=1)

    """
    Case 3: DST check
    Suppose start (which is last_run_time) is in EST while next_run is in EDT, then
    check whether the `next_run` is actually the time specified in the start (i.e. there is not an hour diff due to DST).
    In 2019, DST starts on March 10
    """
    start = eastern_tz.localize(datetime(month=3, day=9, year=2019, hour=10, minute=0))         # EST
    now = eastern_tz.localize(datetime(day=11, month=3, year=2019, hour=1, minute=0))           # EDT
    delta = ffwd(hour=10, year=2019, microsecond=0, minute=0, second=0, day=11, weeks=0, month=3)
    # `next_actual_time` is the next time to run (derived from delta)
    next_actual_time = eastern_tz.localize(datetime(day=11, month=3, year=2019, hour=10, minute=0))         # EDT
    assert start.tzname() == "EST"
    assert now.tzname() == "EDT"
    assert next_actual_time.tzname() == "EDT"
    rem_time = remaining(start, delta, now)
    next_run = now + rem_time
    assert next_run == next_actual_time
Exemple #4
0
 def test_radd_with_unknown_gives_NotImplemented(self):
     x = ffwd(year=2012)
     assert x.__radd__(object()) == NotImplemented
Exemple #5
0
 def test_repr(self):
     x = ffwd(year=2012)
     assert repr(x)
Exemple #6
0
 def test_radd_with_unknown_gives_NotImplemented(self):
     x = ffwd(year=2012)
     assert x.__radd__(object()) == NotImplemented
Exemple #7
0
 def test_repr(self):
     x = ffwd(year=2012)
     assert repr(x)
Exemple #8
0
    def _delta_to_next(self, last_run_at, next_hour, next_minute, next_second):
        """Find next delta.

        Takes a :class:`~datetime.datetime` of last run, next minute and hour,
        and returns a :class:`~celery.utils.time.ffwd` for the next
        scheduled day and time.

        Only called when ``day_of_month`` and/or ``month_of_year``
        cronspec is specified to further limit scheduled task execution.
        """
        datedata = AttributeDict(year=last_run_at.year)
        days_of_month = sorted(self.day_of_month)
        months_of_year = sorted(self.month_of_year)

        def day_out_of_range(year, month, day):
            try:
                datetime(year=year, month=month, day=day)
            except ValueError:
                return True
            return False

        def roll_over():
            for _ in range(2000):
                flag = (datedata.dom == len(days_of_month) or day_out_of_range(
                    datedata.year, months_of_year[datedata.moy],
                    days_of_month[datedata.dom]) or (self.maybe_make_aware(
                        datetime(datedata.year, months_of_year[datedata.moy],
                                 days_of_month[datedata.dom])) < last_run_at))

                if flag:
                    datedata.dom = 0
                    datedata.moy += 1
                    if datedata.moy == len(months_of_year):
                        datedata.moy = 0
                        datedata.year += 1
                else:
                    break
            else:
                # Tried 2000 times, we're most likely in an infinite loop
                raise RuntimeError('unable to rollover, '
                                   'time specification is probably invalid')

        if last_run_at.month in self.month_of_year:
            datedata.dom = bisect(days_of_month, last_run_at.day)
            datedata.moy = bisect_left(months_of_year, last_run_at.month)
        else:
            datedata.dom = 0
            datedata.moy = bisect(months_of_year, last_run_at.month)
            if datedata.moy == len(months_of_year):
                datedata.moy = 0
        roll_over()

        while 1:
            th = datetime(year=datedata.year,
                          month=months_of_year[datedata.moy],
                          day=days_of_month[datedata.dom])
            if th.isoweekday() % 7 in self.day_of_week:
                break
            datedata.dom += 1
            roll_over()

        return ffwd(year=datedata.year,
                    month=months_of_year[datedata.moy],
                    day=days_of_month[datedata.dom],
                    hour=next_hour,
                    minute=next_minute,
                    second=next_second,
                    microsecond=0)
Exemple #9
0
 def test_radd_with_unknown_gives_NotImplemented(self):
     x = ffwd(year=2012)
     self.assertEqual(x.__radd__(object()), NotImplemented)
Exemple #10
0
 def test_repr(self):
     x = ffwd(year=2012)
     self.assertTrue(repr(x))