added celery and tasks but most important added tag_list
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
from .croniter import (
|
||||
croniter,
|
||||
CroniterBadDateError, # noqa
|
||||
CroniterBadCronError, # noqa
|
||||
CroniterNotAlphaError # noqa
|
||||
) # noqa
|
||||
croniter.__name__ # make flake8 happy
|
||||
@@ -0,0 +1,564 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
import re
|
||||
from time import time
|
||||
import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from dateutil.tz import tzutc
|
||||
import calendar
|
||||
|
||||
step_search_re = re.compile(r'^([^-]+)-([^-/]+)(/(.*))?$')
|
||||
search_re = re.compile(r'^([^-]+)-([^-/]+)(/(.*))?$')
|
||||
only_int_re = re.compile(r'^\d+$')
|
||||
any_int_re = re.compile(r'^\d+')
|
||||
star_or_int_re = re.compile(r'^(\d+|\*)$')
|
||||
VALID_LEN_EXPRESSION = [5, 6]
|
||||
|
||||
|
||||
class CroniterError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class CroniterBadCronError(CroniterError):
|
||||
pass
|
||||
|
||||
|
||||
class CroniterBadDateError(CroniterError):
|
||||
pass
|
||||
|
||||
|
||||
class CroniterNotAlphaError(CroniterError):
|
||||
pass
|
||||
|
||||
|
||||
class croniter(object):
|
||||
MONTHS_IN_YEAR = 12
|
||||
RANGES = (
|
||||
(0, 59),
|
||||
(0, 23),
|
||||
(1, 31),
|
||||
(1, 12),
|
||||
(0, 6),
|
||||
(0, 59)
|
||||
)
|
||||
DAYS = (
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
)
|
||||
|
||||
ALPHACONV = (
|
||||
{},
|
||||
{},
|
||||
{"l": "l"},
|
||||
{'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6,
|
||||
'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12},
|
||||
{'sun': 0, 'mon': 1, 'tue': 2, 'wed': 3, 'thu': 4, 'fri': 5, 'sat': 6},
|
||||
{}
|
||||
)
|
||||
|
||||
LOWMAP = (
|
||||
{},
|
||||
{},
|
||||
{0: 1},
|
||||
{0: 1},
|
||||
{7: 0},
|
||||
{},
|
||||
)
|
||||
|
||||
bad_length = 'Exactly 5 or 6 columns has to be specified for iterator' \
|
||||
'expression.'
|
||||
|
||||
def __init__(self, expr_format, start_time=None, ret_type=float,
|
||||
day_or=True):
|
||||
self._ret_type = ret_type
|
||||
self._day_or = day_or
|
||||
|
||||
if start_time is None:
|
||||
start_time = time()
|
||||
|
||||
self.tzinfo = None
|
||||
if isinstance(start_time, datetime.datetime):
|
||||
self.tzinfo = start_time.tzinfo
|
||||
# milliseconds/microseconds rounds
|
||||
if start_time.microsecond:
|
||||
start_time = start_time + relativedelta(seconds=1)
|
||||
start_time = self._datetime_to_timestamp(start_time)
|
||||
|
||||
self.start_time = start_time
|
||||
self.dst_start_time = start_time
|
||||
self.cur = start_time
|
||||
|
||||
self.expanded, self.nth_weekday_of_month = self.expand(expr_format)
|
||||
|
||||
@classmethod
|
||||
def _alphaconv(cls, index, key, expressions):
|
||||
try:
|
||||
return cls.ALPHACONV[index][key.lower()]
|
||||
except KeyError:
|
||||
raise CroniterNotAlphaError(
|
||||
"[{0}] is not acceptable".format(" ".join(expressions)))
|
||||
|
||||
def get_next(self, ret_type=None):
|
||||
return self._get_next(ret_type or self._ret_type, is_prev=False)
|
||||
|
||||
def get_prev(self, ret_type=None):
|
||||
return self._get_next(ret_type or self._ret_type, is_prev=True)
|
||||
|
||||
def get_current(self, ret_type=None):
|
||||
ret_type = ret_type or self._ret_type
|
||||
if issubclass(ret_type, datetime.datetime):
|
||||
return self._timestamp_to_datetime(self.cur)
|
||||
return self.cur
|
||||
|
||||
@classmethod
|
||||
def _datetime_to_timestamp(cls, d):
|
||||
"""
|
||||
Converts a `datetime` object `d` into a UNIX timestamp.
|
||||
"""
|
||||
if d.tzinfo is not None:
|
||||
d = d.replace(tzinfo=None) - d.utcoffset()
|
||||
|
||||
return cls._timedelta_to_seconds(d - datetime.datetime(1970, 1, 1))
|
||||
|
||||
def _timestamp_to_datetime(self, timestamp):
|
||||
"""
|
||||
Converts a UNIX timestamp `timestamp` into a `datetime` object.
|
||||
"""
|
||||
result = datetime.datetime.utcfromtimestamp(timestamp)
|
||||
if self.tzinfo:
|
||||
result = result.replace(tzinfo=tzutc()).astimezone(self.tzinfo)
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def _timedelta_to_seconds(cls, td):
|
||||
"""
|
||||
Converts a 'datetime.timedelta' object `td` into seconds contained in
|
||||
the duration.
|
||||
Note: We cannot use `timedelta.total_seconds()` because this is not
|
||||
supported by Python 2.6.
|
||||
"""
|
||||
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) \
|
||||
/ 10**6
|
||||
|
||||
# iterator protocol, to enable direct use of croniter
|
||||
# objects in a loop, like "for dt in croniter('5 0 * * *'): ..."
|
||||
# or for combining multiple croniters into single
|
||||
# dates feed using 'itertools' module
|
||||
def __iter__(self):
|
||||
return self
|
||||
__next__ = next = get_next
|
||||
|
||||
def all_next(self, ret_type=None):
|
||||
'''Generator of all consecutive dates. Can be used instead of
|
||||
implicit call to __iter__, whenever non-default
|
||||
'ret_type' has to be specified.
|
||||
'''
|
||||
while True:
|
||||
yield self._get_next(ret_type or self._ret_type, is_prev=False)
|
||||
|
||||
def all_prev(self, ret_type=None):
|
||||
'''Generator of all previous dates.'''
|
||||
while True:
|
||||
yield self._get_next(ret_type or self._ret_type, is_prev=True)
|
||||
|
||||
iter = all_next # alias, you can call .iter() instead of .all_next()
|
||||
|
||||
def _get_next(self, ret_type=None, is_prev=False):
|
||||
expanded = self.expanded[:]
|
||||
nth_weekday_of_month = self.nth_weekday_of_month.copy()
|
||||
|
||||
ret_type = ret_type or self._ret_type
|
||||
|
||||
if not issubclass(ret_type, (float, datetime.datetime)):
|
||||
raise TypeError("Invalid ret_type, only 'float' or 'datetime' "
|
||||
"is acceptable.")
|
||||
|
||||
# exception to support day of month and day of week as defined in cron
|
||||
if (expanded[2][0] != '*' and expanded[4][0] != '*') and self._day_or:
|
||||
bak = expanded[4]
|
||||
expanded[4] = ['*']
|
||||
t1 = self._calc(self.cur, expanded, nth_weekday_of_month, is_prev)
|
||||
expanded[4] = bak
|
||||
expanded[2] = ['*']
|
||||
|
||||
t2 = self._calc(self.cur, expanded, nth_weekday_of_month, is_prev)
|
||||
if not is_prev:
|
||||
result = t1 if t1 < t2 else t2
|
||||
else:
|
||||
result = t1 if t1 > t2 else t2
|
||||
else:
|
||||
result = self._calc(self.cur, expanded,
|
||||
nth_weekday_of_month, is_prev)
|
||||
|
||||
# DST Handling for cron job spanning accross days
|
||||
dtstarttime = self._timestamp_to_datetime(self.dst_start_time)
|
||||
dtstarttime_utcoffset = (
|
||||
dtstarttime.utcoffset() or datetime.timedelta(0))
|
||||
dtresult = self._timestamp_to_datetime(result)
|
||||
lag = lag_hours = 0
|
||||
# do we trigger DST on next crontab (handle backward changes)
|
||||
dtresult_utcoffset = dtstarttime_utcoffset
|
||||
if dtresult and self.tzinfo:
|
||||
dtresult_utcoffset = dtresult.utcoffset()
|
||||
lag_hours = (
|
||||
self._timedelta_to_seconds(dtresult - dtstarttime) / (60*60)
|
||||
)
|
||||
lag = self._timedelta_to_seconds(
|
||||
dtresult_utcoffset - dtstarttime_utcoffset
|
||||
)
|
||||
hours_before_midnight = 24 - dtstarttime.hour
|
||||
if dtresult_utcoffset != dtstarttime_utcoffset:
|
||||
if ((lag > 0 and lag_hours >= hours_before_midnight)
|
||||
or (lag < 0 and
|
||||
((3600*lag_hours+abs(lag)) >= hours_before_midnight*3600))
|
||||
):
|
||||
dtresult = dtresult - datetime.timedelta(seconds=lag)
|
||||
result = self._datetime_to_timestamp(dtresult)
|
||||
self.dst_start_time = result
|
||||
self.cur = result
|
||||
if issubclass(ret_type, datetime.datetime):
|
||||
result = dtresult
|
||||
return result
|
||||
|
||||
def _calc(self, now, expanded, nth_weekday_of_month, is_prev):
|
||||
if is_prev:
|
||||
nearest_diff_method = self._get_prev_nearest_diff
|
||||
sign = -1
|
||||
offset = (len(expanded) == 6 or now % 60 > 0) and 1 or 60
|
||||
else:
|
||||
nearest_diff_method = self._get_next_nearest_diff
|
||||
sign = 1
|
||||
offset = (len(expanded) == 6) and 1 or 60
|
||||
|
||||
dst = now = self._timestamp_to_datetime(now + sign * offset)
|
||||
|
||||
month, year = dst.month, dst.year
|
||||
current_year = now.year
|
||||
DAYS = self.DAYS
|
||||
|
||||
def proc_month(d):
|
||||
if expanded[3][0] != '*':
|
||||
diff_month = nearest_diff_method(
|
||||
d.month, expanded[3], self.MONTHS_IN_YEAR)
|
||||
days = DAYS[month - 1]
|
||||
if month == 2 and self.is_leap(year) is True:
|
||||
days += 1
|
||||
|
||||
reset_day = 1
|
||||
|
||||
if diff_month is not None and diff_month != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(months=diff_month)
|
||||
reset_day = DAYS[d.month - 1]
|
||||
d += relativedelta(
|
||||
day=reset_day, hour=23, minute=59, second=59)
|
||||
else:
|
||||
d += relativedelta(months=diff_month, day=reset_day,
|
||||
hour=0, minute=0, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_day_of_month(d):
|
||||
if expanded[2][0] != '*':
|
||||
days = DAYS[month - 1]
|
||||
if month == 2 and self.is_leap(year) is True:
|
||||
days += 1
|
||||
if 'l' in expanded[2] and days == d.day:
|
||||
return False, d
|
||||
|
||||
if is_prev:
|
||||
days_in_prev_month = DAYS[
|
||||
(month - 2) % self.MONTHS_IN_YEAR]
|
||||
diff_day = nearest_diff_method(
|
||||
d.day, expanded[2], days_in_prev_month)
|
||||
else:
|
||||
diff_day = nearest_diff_method(d.day, expanded[2], days)
|
||||
|
||||
if diff_day is not None and diff_day != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(
|
||||
days=diff_day, hour=23, minute=59, second=59)
|
||||
else:
|
||||
d += relativedelta(
|
||||
days=diff_day, hour=0, minute=0, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_day_of_week(d):
|
||||
if expanded[4][0] != '*':
|
||||
diff_day_of_week = nearest_diff_method(
|
||||
d.isoweekday() % 7, expanded[4], 7)
|
||||
if diff_day_of_week is not None and diff_day_of_week != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(days=diff_day_of_week,
|
||||
hour=23, minute=59, second=59)
|
||||
else:
|
||||
d += relativedelta(days=diff_day_of_week,
|
||||
hour=0, minute=0, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_day_of_week_nth(d):
|
||||
if '*' in nth_weekday_of_month:
|
||||
s = nth_weekday_of_month['*']
|
||||
for i in range(0, 7):
|
||||
if i in nth_weekday_of_month:
|
||||
nth_weekday_of_month[i].update(s)
|
||||
else:
|
||||
nth_weekday_of_month[i] = s
|
||||
del nth_weekday_of_month['*']
|
||||
|
||||
candidates = []
|
||||
for wday, nth in nth_weekday_of_month.items():
|
||||
w = (wday + 6) % 7
|
||||
c = calendar.Calendar(w).monthdayscalendar(d.year, d.month)
|
||||
if c[0][0] == 0: c.pop(0)
|
||||
for n in nth:
|
||||
if len(c) < n:
|
||||
continue
|
||||
candidate = c[n - 1][0]
|
||||
if (
|
||||
(is_prev and candidate <= d.day) or
|
||||
(not is_prev and d.day <= candidate)
|
||||
):
|
||||
candidates.append(candidate)
|
||||
|
||||
if not candidates:
|
||||
if is_prev:
|
||||
d += relativedelta(days=-d.day,
|
||||
hour=23, minute=59, second=59)
|
||||
else:
|
||||
days = DAYS[month - 1]
|
||||
if month == 2 and self.is_leap(year) is True:
|
||||
days += 1
|
||||
d += relativedelta(days=(days - d.day + 1),
|
||||
hour=0, minute=0, second=0)
|
||||
return True, d
|
||||
|
||||
candidates.sort()
|
||||
diff_day = (candidates[-1] if is_prev else candidates[0]) - d.day
|
||||
if diff_day != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(days=diff_day,
|
||||
hour=23, minute=59, second=59)
|
||||
else:
|
||||
d += relativedelta(days=diff_day,
|
||||
hour=0, minute=0, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_hour(d):
|
||||
if expanded[1][0] != '*':
|
||||
diff_hour = nearest_diff_method(d.hour, expanded[1], 24)
|
||||
if diff_hour is not None and diff_hour != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(
|
||||
hours=diff_hour, minute=59, second=59)
|
||||
else:
|
||||
d += relativedelta(hours=diff_hour, minute=0, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_minute(d):
|
||||
if expanded[0][0] != '*':
|
||||
diff_min = nearest_diff_method(d.minute, expanded[0], 60)
|
||||
if diff_min is not None and diff_min != 0:
|
||||
if is_prev:
|
||||
d += relativedelta(minutes=diff_min, second=59)
|
||||
else:
|
||||
d += relativedelta(minutes=diff_min, second=0)
|
||||
return True, d
|
||||
return False, d
|
||||
|
||||
def proc_second(d):
|
||||
if len(expanded) == 6:
|
||||
if expanded[5][0] != '*':
|
||||
diff_sec = nearest_diff_method(d.second, expanded[5], 60)
|
||||
if diff_sec is not None and diff_sec != 0:
|
||||
d += relativedelta(seconds=diff_sec)
|
||||
return True, d
|
||||
else:
|
||||
d += relativedelta(second=0)
|
||||
return False, d
|
||||
|
||||
procs = [proc_month,
|
||||
proc_day_of_month,
|
||||
(proc_day_of_week_nth if nth_weekday_of_month
|
||||
else proc_day_of_week),
|
||||
proc_hour,
|
||||
proc_minute,
|
||||
proc_second]
|
||||
|
||||
while abs(year - current_year) <= 1:
|
||||
next = False
|
||||
for proc in procs:
|
||||
(changed, dst) = proc(dst)
|
||||
if changed:
|
||||
month, year = dst.month, dst.year
|
||||
next = True
|
||||
break
|
||||
if next:
|
||||
continue
|
||||
return self._datetime_to_timestamp(dst.replace(microsecond=0))
|
||||
|
||||
if is_prev:
|
||||
raise CroniterBadDateError("failed to find prev date")
|
||||
raise CroniterBadDateError("failed to find next date")
|
||||
|
||||
def _get_next_nearest(self, x, to_check):
|
||||
small = [item for item in to_check if item < x]
|
||||
large = [item for item in to_check if item >= x]
|
||||
large.extend(small)
|
||||
return large[0]
|
||||
|
||||
def _get_prev_nearest(self, x, to_check):
|
||||
small = [item for item in to_check if item <= x]
|
||||
large = [item for item in to_check if item > x]
|
||||
small.reverse()
|
||||
large.reverse()
|
||||
small.extend(large)
|
||||
return small[0]
|
||||
|
||||
def _get_next_nearest_diff(self, x, to_check, range_val):
|
||||
for i, d in enumerate(to_check):
|
||||
if d == "l":
|
||||
# if 'l' then it is the last day of month
|
||||
# => its value of range_val
|
||||
d = range_val
|
||||
if d >= x:
|
||||
return d - x
|
||||
return to_check[0] - x + range_val
|
||||
|
||||
def _get_prev_nearest_diff(self, x, to_check, range_val):
|
||||
candidates = to_check[:]
|
||||
candidates.reverse()
|
||||
for d in candidates:
|
||||
if d != 'l' and d <= x:
|
||||
return d - x
|
||||
if 'l' in candidates:
|
||||
return -x
|
||||
candidate = candidates[0]
|
||||
for c in candidates:
|
||||
# fixed: c < range_val
|
||||
# this code will reject all 31 day of month, 12 month, 59 second,
|
||||
# 23 hour and so on.
|
||||
# if candidates has just a element, this will not harmful.
|
||||
# but candidates have multiple elements, then values equal to
|
||||
# range_val will rejected.
|
||||
if c <= range_val:
|
||||
candidate = c
|
||||
break
|
||||
|
||||
return (candidate - x - range_val)
|
||||
|
||||
def is_leap(self, year):
|
||||
if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def expand(cls, expr_format):
|
||||
expressions = expr_format.split()
|
||||
|
||||
if len(expressions) not in VALID_LEN_EXPRESSION:
|
||||
raise CroniterBadCronError(cls.bad_length)
|
||||
|
||||
expanded = []
|
||||
nth_weekday_of_month = {}
|
||||
|
||||
for i, expr in enumerate(expressions):
|
||||
e_list = expr.split(',')
|
||||
res = []
|
||||
|
||||
while len(e_list) > 0:
|
||||
e = e_list.pop()
|
||||
|
||||
if i == 4:
|
||||
e, sep, nth = str(e).partition('#')
|
||||
if nth and not re.match(r'[1-5]', nth):
|
||||
raise CroniterBadDateError(
|
||||
"[{0}] is not acceptable".format(expr_format))
|
||||
|
||||
t = re.sub(r'^\*(\/.+)$', r'%d-%d\1' % (
|
||||
cls.RANGES[i][0],
|
||||
cls.RANGES[i][1]),
|
||||
str(e))
|
||||
m = search_re.search(t)
|
||||
|
||||
if not m:
|
||||
t = re.sub(r'^(.+)\/(.+)$', r'\1-%d/\2' % (
|
||||
cls.RANGES[i][1]),
|
||||
str(e))
|
||||
m = step_search_re.search(t)
|
||||
|
||||
if m:
|
||||
(low, high, step) = m.group(1), m.group(2), m.group(4) or 1
|
||||
|
||||
if not any_int_re.search(low):
|
||||
low = "{0}".format(cls._alphaconv(i, low, expressions))
|
||||
|
||||
if not any_int_re.search(high):
|
||||
high = "{0}".format(cls._alphaconv(i, high, expressions))
|
||||
|
||||
if (
|
||||
not low or not high or int(low) > int(high)
|
||||
or not only_int_re.search(str(step))
|
||||
):
|
||||
raise CroniterBadDateError(
|
||||
"[{0}] is not acceptable".format(expr_format))
|
||||
|
||||
low, high, step = map(int, [low, high, step])
|
||||
rng = range(low, high + 1, step)
|
||||
e_list += (["{0}#{1}".format(item, nth) for item in rng]
|
||||
if i == 4 and nth else rng)
|
||||
else:
|
||||
if t.startswith('-'):
|
||||
raise CroniterBadCronError(
|
||||
"[{0}] is not acceptable,\
|
||||
negative numbers not allowed".format(
|
||||
expr_format))
|
||||
if not star_or_int_re.search(t):
|
||||
t = cls._alphaconv(i, t, expressions)
|
||||
|
||||
try:
|
||||
t = int(t)
|
||||
except:
|
||||
pass
|
||||
|
||||
if t in cls.LOWMAP[i]:
|
||||
t = cls.LOWMAP[i][t]
|
||||
|
||||
if (
|
||||
t not in ["*", "l"]
|
||||
and (int(t) < cls.RANGES[i][0] or
|
||||
int(t) > cls.RANGES[i][1])
|
||||
):
|
||||
raise CroniterBadCronError(
|
||||
"[{0}] is not acceptable, out of range".format(
|
||||
expr_format))
|
||||
|
||||
res.append(t)
|
||||
|
||||
if i == 4 and nth:
|
||||
if t not in nth_weekday_of_month:
|
||||
nth_weekday_of_month[t] = set()
|
||||
nth_weekday_of_month[t].add(int(nth))
|
||||
|
||||
res.sort()
|
||||
expanded.append(['*'] if (len(res) == 1
|
||||
and res[0] == '*')
|
||||
else res)
|
||||
|
||||
return expanded, nth_weekday_of_month
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, expression):
|
||||
try:
|
||||
cls.expand(expression)
|
||||
except CroniterError:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
@@ -0,0 +1,13 @@
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
'''
|
||||
We use this base class for all the tests in this package.
|
||||
If necessary, we can put common utility or setup code in here.
|
||||
'''
|
||||
|
||||
# vim:set ft=python:
|
||||
@@ -0,0 +1,837 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
import pytz
|
||||
from croniter import croniter, CroniterBadDateError, CroniterBadCronError, CroniterNotAlphaError
|
||||
from croniter.tests import base
|
||||
|
||||
|
||||
class CroniterTest(base.TestCase):
|
||||
|
||||
def testSecond(self):
|
||||
base = datetime(2012, 4, 6, 13, 26, 10)
|
||||
itr = croniter('*/1 * * * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(base.year, n1.year)
|
||||
self.assertEqual(base.month, n1.month)
|
||||
self.assertEqual(base.day, n1.day)
|
||||
self.assertEqual(base.hour, n1.hour)
|
||||
self.assertEqual(base.minute, n1.minute)
|
||||
self.assertEqual(base.second + 1, n1.second)
|
||||
|
||||
def testSecondRepeat(self):
|
||||
base = datetime(2012, 4, 6, 13, 26, 36)
|
||||
itr = croniter('* * * * * */15', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n2 = itr.get_next(datetime)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(base.year, n1.year)
|
||||
self.assertEqual(base.month, n1.month)
|
||||
self.assertEqual(base.day, n1.day)
|
||||
self.assertEqual(base.hour, n1.hour)
|
||||
self.assertEqual(base.minute, n1.minute)
|
||||
self.assertEqual(45, n1.second)
|
||||
self.assertEqual(base.year, n2.year)
|
||||
self.assertEqual(base.month, n2.month)
|
||||
self.assertEqual(base.day, n2.day)
|
||||
self.assertEqual(base.hour, n2.hour)
|
||||
self.assertEqual(base.minute + 1, n2.minute)
|
||||
self.assertEqual(0, n2.second)
|
||||
self.assertEqual(base.year, n3.year)
|
||||
self.assertEqual(base.month, n3.month)
|
||||
self.assertEqual(base.day, n3.day)
|
||||
self.assertEqual(base.hour, n3.hour)
|
||||
self.assertEqual(base.minute + 1, n3.minute)
|
||||
self.assertEqual(15, n3.second)
|
||||
|
||||
def testMinute(self):
|
||||
# minute asterisk
|
||||
base = datetime(2010, 1, 23, 12, 18)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
n1 = itr.get_next(datetime) # 19
|
||||
self.assertEqual(base.year, n1.year)
|
||||
self.assertEqual(base.month, n1.month)
|
||||
self.assertEqual(base.day, n1.day)
|
||||
self.assertEqual(base.hour, n1.hour)
|
||||
self.assertEqual(base.minute, n1.minute - 1)
|
||||
for i in range(39): # ~ 58
|
||||
itr.get_next()
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.minute, 59)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.minute, 0)
|
||||
self.assertEqual(n3.hour, 13)
|
||||
|
||||
itr = croniter('*/5 * * * *', base)
|
||||
n4 = itr.get_next(datetime)
|
||||
self.assertEqual(n4.minute, 20)
|
||||
for i in range(6):
|
||||
itr.get_next()
|
||||
n5 = itr.get_next(datetime)
|
||||
self.assertEqual(n5.minute, 55)
|
||||
n6 = itr.get_next(datetime)
|
||||
self.assertEqual(n6.minute, 0)
|
||||
self.assertEqual(n6.hour, 13)
|
||||
|
||||
def testHour(self):
|
||||
base = datetime(2010, 1, 24, 12, 2)
|
||||
itr = croniter('0 */3 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 15)
|
||||
self.assertEqual(n1.minute, 0)
|
||||
for i in range(2):
|
||||
itr.get_next()
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.hour, 0)
|
||||
self.assertEqual(n2.day, 25)
|
||||
|
||||
def testDay(self):
|
||||
base = datetime(2010, 2, 24, 12, 9)
|
||||
itr = croniter('0 0 */3 * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
# 1 4 7 10 13 16 19 22 25 28
|
||||
self.assertEqual(n1.day, 25)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.day, 28)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.day, 1)
|
||||
self.assertEqual(n3.month, 3)
|
||||
|
||||
# test leap year
|
||||
base = datetime(1996, 2, 27)
|
||||
itr = croniter('0 0 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.day, 28)
|
||||
self.assertEqual(n1.month, 2)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.day, 29)
|
||||
self.assertEqual(n2.month, 2)
|
||||
|
||||
base2 = datetime(2000, 2, 27)
|
||||
itr2 = croniter('0 0 * * *', base2)
|
||||
n3 = itr2.get_next(datetime)
|
||||
self.assertEqual(n3.day, 28)
|
||||
self.assertEqual(n3.month, 2)
|
||||
n4 = itr2.get_next(datetime)
|
||||
self.assertEqual(n4.day, 29)
|
||||
self.assertEqual(n4.month, 2)
|
||||
|
||||
def testWeekDay(self):
|
||||
base = datetime(2010, 2, 25)
|
||||
itr = croniter('0 0 * * sat', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.isoweekday(), 6)
|
||||
self.assertEqual(n1.day, 27)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.isoweekday(), 6)
|
||||
self.assertEqual(n2.day, 6)
|
||||
self.assertEqual(n2.month, 3)
|
||||
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 1 * wed', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.month, 1)
|
||||
self.assertEqual(n1.day, 27)
|
||||
self.assertEqual(n1.year, 2010)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.month, 2)
|
||||
self.assertEqual(n2.day, 1)
|
||||
self.assertEqual(n2.year, 2010)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.month, 2)
|
||||
self.assertEqual(n3.day, 3)
|
||||
self.assertEqual(n3.year, 2010)
|
||||
|
||||
def testNthWeekDay(self):
|
||||
base = datetime(2010, 2, 25)
|
||||
itr = croniter('0 0 * * sat#1', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.isoweekday(), 6)
|
||||
self.assertEqual(n1.day, 6)
|
||||
self.assertEqual(n1.month, 3)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.isoweekday(), 6)
|
||||
self.assertEqual(n2.day, 3)
|
||||
self.assertEqual(n2.month, 4)
|
||||
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 * * wed#5', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.month, 3)
|
||||
self.assertEqual(n1.day, 31)
|
||||
self.assertEqual(n1.year, 2010)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.month, 6)
|
||||
self.assertEqual(n2.day, 30)
|
||||
self.assertEqual(n2.year, 2010)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.month, 9)
|
||||
self.assertEqual(n3.day, 29)
|
||||
self.assertEqual(n3.year, 2010)
|
||||
|
||||
def testWeekDayDayAnd(self):
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 1 * mon', base, day_or=False)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 1)
|
||||
self.assertEqual(n1.year, 2010)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.month, 3)
|
||||
self.assertEqual(n2.day, 1)
|
||||
self.assertEqual(n2.year, 2010)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.month, 11)
|
||||
self.assertEqual(n3.day, 1)
|
||||
self.assertEqual(n3.year, 2010)
|
||||
|
||||
def testMonth(self):
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 1 * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 1)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.month, 3)
|
||||
self.assertEqual(n2.day, 1)
|
||||
for i in range(8):
|
||||
itr.get_next()
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.month, 12)
|
||||
self.assertEqual(n3.year, 2010)
|
||||
n4 = itr.get_next(datetime)
|
||||
self.assertEqual(n4.month, 1)
|
||||
self.assertEqual(n4.year, 2011)
|
||||
|
||||
def testLastDayOfMonth(self):
|
||||
base = datetime(2015, 9, 4)
|
||||
itr = croniter('0 0 l * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.month, 9)
|
||||
self.assertEqual(n1.day, 30)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.month, 10)
|
||||
self.assertEqual(n2.day, 31)
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(n3.month, 11)
|
||||
self.assertEqual(n3.day, 30)
|
||||
n4 = itr.get_next(datetime)
|
||||
self.assertEqual(n4.month, 12)
|
||||
self.assertEqual(n4.day, 31)
|
||||
|
||||
def testPrevLastDayOfMonth(self):
|
||||
base = datetime(2009, 12, 31, hour=20)
|
||||
itr = croniter('0 0 l * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 12)
|
||||
self.assertEqual(n1.day, 31)
|
||||
|
||||
base = datetime(2009, 12, 31)
|
||||
itr = croniter('0 0 l * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 11)
|
||||
self.assertEqual(n1.day, 30)
|
||||
|
||||
base = datetime(2010, 1, 5)
|
||||
itr = croniter('0 0 l * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 12)
|
||||
self.assertEqual(n1.day, 31)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 11)
|
||||
self.assertEqual(n1.day, 30)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 10)
|
||||
self.assertEqual(n1.day, 31)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 9)
|
||||
self.assertEqual(n1.day, 30)
|
||||
|
||||
base = datetime(2010, 1, 31, minute=2)
|
||||
itr = croniter('* * l * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 1)
|
||||
self.assertEqual(n1.day, 31)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 1)
|
||||
self.assertEqual(n1.day, 31)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 12)
|
||||
self.assertEqual(n1.day, 31)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.month, 12)
|
||||
self.assertEqual(n1.day, 31)
|
||||
|
||||
def testError(self):
|
||||
itr = croniter('* * * * *')
|
||||
self.assertRaises(TypeError, itr.get_next, str)
|
||||
self.assertRaises(ValueError, croniter, '* * * *')
|
||||
self.assertRaises(ValueError, croniter, '* * 5-1 * *')
|
||||
self.assertRaises(ValueError, croniter, '-90 * * * *')
|
||||
self.assertRaises(ValueError, croniter, 'a * * * *')
|
||||
self.assertRaises(ValueError, croniter, '* * * janu-jun *')
|
||||
|
||||
def testSundayToThursdayWithAlphaConversion(self):
|
||||
base = datetime(2010, 8, 25, 15, 56) # wednesday
|
||||
itr = croniter("30 22 * * sun-thu", base)
|
||||
next = itr.get_next(datetime)
|
||||
|
||||
self.assertEqual(base.year, next.year)
|
||||
self.assertEqual(base.month, next.month)
|
||||
self.assertEqual(base.day, next.day)
|
||||
self.assertEqual(22, next.hour)
|
||||
self.assertEqual(30, next.minute)
|
||||
|
||||
def testPrevMinute(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
self.assertEqual(base.year, prev.year)
|
||||
self.assertEqual(base.month, prev.month)
|
||||
self.assertEqual(base.day, prev.day)
|
||||
self.assertEqual(base.hour, prev.hour)
|
||||
self.assertEqual(base.minute, prev.minute + 1)
|
||||
|
||||
base = datetime(2010, 8, 25, 15, 0)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
self.assertEqual(base.year, prev.year)
|
||||
self.assertEqual(base.month, prev.month)
|
||||
self.assertEqual(base.day, prev.day)
|
||||
self.assertEqual(base.hour, prev.hour + 1)
|
||||
self.assertEqual(59, prev.minute)
|
||||
|
||||
base = datetime(2010, 8, 25, 0, 0)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
self.assertEqual(base.year, prev.year)
|
||||
self.assertEqual(base.month, prev.month)
|
||||
self.assertEqual(base.day, prev.day + 1)
|
||||
self.assertEqual(23, prev.hour)
|
||||
self.assertEqual(59, prev.minute)
|
||||
|
||||
def testPrevDayOfMonthWithCrossing(self):
|
||||
"""
|
||||
Test getting previous occurrence that crosses into previous month.
|
||||
"""
|
||||
base = datetime(2012, 3, 15, 0, 0)
|
||||
itr = croniter('0 0 22 * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
self.assertEqual(prev.year, 2012)
|
||||
self.assertEqual(prev.month, 2)
|
||||
self.assertEqual(prev.day, 22)
|
||||
self.assertEqual(prev.hour, 0)
|
||||
self.assertEqual(prev.minute, 0)
|
||||
|
||||
def testPrevWeekDay(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('0 0 * * sat,sun', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, base.month)
|
||||
self.assertEqual(prev1.day, 22)
|
||||
self.assertEqual(prev1.hour, 0)
|
||||
self.assertEqual(prev1.minute, 0)
|
||||
|
||||
prev2 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev2.year, base.year)
|
||||
self.assertEqual(prev2.month, base.month)
|
||||
self.assertEqual(prev2.day, 21)
|
||||
self.assertEqual(prev2.hour, 0)
|
||||
self.assertEqual(prev2.minute, 0)
|
||||
|
||||
prev3 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev3.year, base.year)
|
||||
self.assertEqual(prev3.month, base.month)
|
||||
self.assertEqual(prev3.day, 15)
|
||||
self.assertEqual(prev3.hour, 0)
|
||||
self.assertEqual(prev3.minute, 0)
|
||||
|
||||
def testPrevNthWeekDay(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('0 0 * * sat#1,sun#2', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, base.month)
|
||||
self.assertEqual(prev1.day, 8)
|
||||
self.assertEqual(prev1.hour, 0)
|
||||
self.assertEqual(prev1.minute, 0)
|
||||
|
||||
prev2 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev2.year, base.year)
|
||||
self.assertEqual(prev2.month, base.month)
|
||||
self.assertEqual(prev2.day, 7)
|
||||
self.assertEqual(prev2.hour, 0)
|
||||
self.assertEqual(prev2.minute, 0)
|
||||
|
||||
prev3 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev3.year, base.year)
|
||||
self.assertEqual(prev3.month, 7)
|
||||
self.assertEqual(prev3.day, 11)
|
||||
self.assertEqual(prev3.hour, 0)
|
||||
self.assertEqual(prev3.minute, 0)
|
||||
|
||||
def testPrevWeekDay2(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('10 0 * * 0', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
self.assertEqual(prev.day, 22)
|
||||
self.assertEqual(prev.hour, 0)
|
||||
self.assertEqual(prev.minute, 10)
|
||||
|
||||
def testISOWeekday(self):
|
||||
base = datetime(2010, 2, 25)
|
||||
itr = croniter('0 0 * * 7', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.isoweekday(), 7)
|
||||
self.assertEqual(n1.day, 28)
|
||||
n2 = itr.get_next(datetime)
|
||||
self.assertEqual(n2.isoweekday(), 7)
|
||||
self.assertEqual(n2.day, 7)
|
||||
self.assertEqual(n2.month, 3)
|
||||
|
||||
def testBug1(self):
|
||||
base = datetime(2012, 2, 24)
|
||||
itr = croniter('5 0 */2 * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.hour, 0)
|
||||
self.assertEqual(n1.minute, 5)
|
||||
self.assertEqual(n1.month, 2)
|
||||
# month starts from 1, 3 .... then 21, 23
|
||||
# so correct is not 22 but 23
|
||||
self.assertEqual(n1.day, 23)
|
||||
|
||||
def testBug2(self):
|
||||
base = datetime(2012, 1, 1, 0, 0)
|
||||
iter = croniter('0 * * 3 *', base)
|
||||
n1 = iter.get_next(datetime)
|
||||
self.assertEqual(n1.year, base.year)
|
||||
self.assertEqual(n1.month, 3)
|
||||
self.assertEqual(n1.day, base.day)
|
||||
self.assertEqual(n1.hour, base.hour)
|
||||
self.assertEqual(n1.minute, base.minute)
|
||||
|
||||
n2 = iter.get_next(datetime)
|
||||
self.assertEqual(n2.year, base.year)
|
||||
self.assertEqual(n2.month, 3)
|
||||
self.assertEqual(n2.day, base.day)
|
||||
self.assertEqual(n2.hour, base.hour + 1)
|
||||
self.assertEqual(n2.minute, base.minute)
|
||||
|
||||
n3 = iter.get_next(datetime)
|
||||
self.assertEqual(n3.year, base.year)
|
||||
self.assertEqual(n3.month, 3)
|
||||
self.assertEqual(n3.day, base.day)
|
||||
self.assertEqual(n3.hour, base.hour + 2)
|
||||
self.assertEqual(n3.minute, base.minute)
|
||||
|
||||
def testBug3(self):
|
||||
base = datetime(2013, 3, 1, 12, 17, 34, 257877)
|
||||
c = croniter('00 03 16,30 * *', base)
|
||||
|
||||
n1 = c.get_next(datetime)
|
||||
self.assertEqual(n1.month, 3)
|
||||
self.assertEqual(n1.day, 16)
|
||||
|
||||
n2 = c.get_next(datetime)
|
||||
self.assertEqual(n2.month, 3)
|
||||
self.assertEqual(n2.day, 30)
|
||||
|
||||
n3 = c.get_next(datetime)
|
||||
self.assertEqual(n3.month, 4)
|
||||
self.assertEqual(n3.day, 16)
|
||||
|
||||
n4 = c.get_prev(datetime)
|
||||
self.assertEqual(n4.month, 3)
|
||||
self.assertEqual(n4.day, 30)
|
||||
|
||||
n5 = c.get_prev(datetime)
|
||||
self.assertEqual(n5.month, 3)
|
||||
self.assertEqual(n5.day, 16)
|
||||
|
||||
n6 = c.get_prev(datetime)
|
||||
self.assertEqual(n6.month, 2)
|
||||
self.assertEqual(n6.day, 16)
|
||||
|
||||
def test_bug34(self):
|
||||
base = datetime(2012, 2, 24, 0, 0, 0)
|
||||
itr = croniter('* * 31 2 *', base)
|
||||
try:
|
||||
itr.get_next(datetime)
|
||||
except (CroniterBadDateError,) as ex:
|
||||
self.assertEqual("{0}".format(ex),
|
||||
'failed to find next date')
|
||||
|
||||
def testBug57(self):
|
||||
base = datetime(2012, 2, 24, 0, 0, 0)
|
||||
itr = croniter('0 4/6 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 4)
|
||||
self.assertEqual(n1.minute, 0)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 24)
|
||||
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.hour, 22)
|
||||
self.assertEqual(n1.minute, 0)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 23)
|
||||
|
||||
itr = croniter('0 0/6 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 6)
|
||||
self.assertEqual(n1.minute, 0)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 24)
|
||||
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(n1.hour, 0)
|
||||
self.assertEqual(n1.minute, 0)
|
||||
self.assertEqual(n1.month, 2)
|
||||
self.assertEqual(n1.day, 24)
|
||||
|
||||
def test_multiple_months(self):
|
||||
base = datetime(2016, 3, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1 3,6,9,12 *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 0)
|
||||
self.assertEqual(n1.month, 6)
|
||||
self.assertEqual(n1.day, 1)
|
||||
self.assertEqual(n1.year, 2016)
|
||||
|
||||
base = datetime(2016, 2, 15, 0, 0, 0)
|
||||
itr = croniter('0 0 1 3,6,9,12 *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 0)
|
||||
self.assertEqual(n1.month, 3)
|
||||
self.assertEqual(n1.day, 1)
|
||||
self.assertEqual(n1.year, 2016)
|
||||
|
||||
base = datetime(2016, 12, 3, 10, 0, 0)
|
||||
itr = croniter('0 0 1 3,6,9,12 *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.hour, 0)
|
||||
self.assertEqual(n1.month, 3)
|
||||
self.assertEqual(n1.day, 1)
|
||||
self.assertEqual(n1.year, 2017)
|
||||
|
||||
# The result with this parameters was incorrect.
|
||||
# self.assertEqual(p1.month, 12
|
||||
# AssertionError: 9 != 12
|
||||
base = datetime(2016, 3, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1 3,6,9,12 *', base)
|
||||
p1 = itr.get_prev(datetime)
|
||||
self.assertEqual(p1.hour, 0)
|
||||
self.assertEqual(p1.month, 12)
|
||||
self.assertEqual(p1.day, 1)
|
||||
self.assertEqual(p1.year, 2015)
|
||||
|
||||
# check my change resolves another hidden bug.
|
||||
base = datetime(2016, 2, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1,15,31 * *', base)
|
||||
p1 = itr.get_prev(datetime)
|
||||
self.assertEqual(p1.hour, 0)
|
||||
self.assertEqual(p1.month, 1)
|
||||
self.assertEqual(p1.day, 31)
|
||||
self.assertEqual(p1.year, 2016)
|
||||
|
||||
base = datetime(2016, 6, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1 3,6,9,12 *', base)
|
||||
p1 = itr.get_prev(datetime)
|
||||
self.assertEqual(p1.hour, 0)
|
||||
self.assertEqual(p1.month, 3)
|
||||
self.assertEqual(p1.day, 1)
|
||||
self.assertEqual(p1.year, 2016)
|
||||
|
||||
base = datetime(2016, 3, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1 1,3,6,9,12 *', base)
|
||||
p1 = itr.get_prev(datetime)
|
||||
self.assertEqual(p1.hour, 0)
|
||||
self.assertEqual(p1.month, 1)
|
||||
self.assertEqual(p1.day, 1)
|
||||
self.assertEqual(p1.year, 2016)
|
||||
|
||||
base = datetime(2016, 3, 1, 0, 0, 0)
|
||||
itr = croniter('0 0 1 1,3,6,9,12 *', base)
|
||||
p1 = itr.get_prev(datetime)
|
||||
self.assertEqual(p1.hour, 0)
|
||||
self.assertEqual(p1.month, 1)
|
||||
self.assertEqual(p1.day, 1)
|
||||
self.assertEqual(p1.year, 2016)
|
||||
|
||||
def test_rangeGenerator(self):
|
||||
base = datetime(2013, 3, 4, 0, 0)
|
||||
itr = croniter('1-9/2 0 1 * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n2 = itr.get_next(datetime)
|
||||
n3 = itr.get_next(datetime)
|
||||
n4 = itr.get_next(datetime)
|
||||
n5 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.minute, 1)
|
||||
self.assertEqual(n2.minute, 3)
|
||||
self.assertEqual(n3.minute, 5)
|
||||
self.assertEqual(n4.minute, 7)
|
||||
self.assertEqual(n5.minute, 9)
|
||||
|
||||
def testPreviousHour(self):
|
||||
base = datetime(2012, 6, 23, 17, 41)
|
||||
itr = croniter('* 10 * * *', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, base.month)
|
||||
self.assertEqual(prev1.day, base.day)
|
||||
self.assertEqual(prev1.hour, 10)
|
||||
self.assertEqual(prev1.minute, 59)
|
||||
|
||||
def testPreviousDay(self):
|
||||
base = datetime(2012, 6, 27, 0, 15)
|
||||
itr = croniter('* * 26 * *', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, base.month)
|
||||
self.assertEqual(prev1.day, 26)
|
||||
self.assertEqual(prev1.hour, 23)
|
||||
self.assertEqual(prev1.minute, 59)
|
||||
|
||||
def testPreviousMonth(self):
|
||||
base = datetime(2012, 6, 18, 0, 15)
|
||||
itr = croniter('* * * 5 *', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, 5)
|
||||
self.assertEqual(prev1.day, 31)
|
||||
self.assertEqual(prev1.hour, 23)
|
||||
self.assertEqual(prev1.minute, 59)
|
||||
|
||||
def testPreviousDow(self):
|
||||
base = datetime(2012, 5, 13, 18, 48)
|
||||
itr = croniter('* * * * sat', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
self.assertEqual(prev1.year, base.year)
|
||||
self.assertEqual(prev1.month, base.month)
|
||||
self.assertEqual(prev1.day, 12)
|
||||
self.assertEqual(prev1.hour, 23)
|
||||
self.assertEqual(prev1.minute, 59)
|
||||
|
||||
def testGetCurrent(self):
|
||||
base = datetime(2012, 9, 25, 11, 24)
|
||||
itr = croniter('* * * * *', base)
|
||||
res = itr.get_current(datetime)
|
||||
self.assertEqual(base.year, res.year)
|
||||
self.assertEqual(base.month, res.month)
|
||||
self.assertEqual(base.day, res.day)
|
||||
self.assertEqual(base.hour, res.hour)
|
||||
self.assertEqual(base.minute, res.minute)
|
||||
|
||||
def testTimezone(self):
|
||||
base = datetime(2013, 3, 4, 12, 15)
|
||||
itr = croniter('* * * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
self.assertEqual(n1.tzinfo, None)
|
||||
|
||||
tokyo = pytz.timezone('Asia/Tokyo')
|
||||
itr2 = croniter('* * * * *', tokyo.localize(base))
|
||||
n2 = itr2.get_next(datetime)
|
||||
self.assertEqual(n2.tzinfo.zone, 'Asia/Tokyo')
|
||||
|
||||
def testInitNoStartTime(self):
|
||||
itr = croniter('* * * * *')
|
||||
sleep(.01)
|
||||
itr2 = croniter('* * * * *')
|
||||
# Greater dosnt exists in py26
|
||||
self.assertTrue(itr2.cur > itr.cur)
|
||||
|
||||
def assertScheduleTimezone(self, callback, expected_schedule):
|
||||
for expected_date, expected_offset in expected_schedule:
|
||||
d = callback()
|
||||
self.assertEqual(expected_date, d.replace(tzinfo=None))
|
||||
self.assertEqual(expected_offset,
|
||||
croniter._timedelta_to_seconds(d.utcoffset()))
|
||||
|
||||
def testTimezoneWinterTime(self):
|
||||
tz = pytz.timezone('Europe/Athens')
|
||||
|
||||
expected_schedule = [
|
||||
(datetime(2013, 10, 27, 2, 30, 0), 10800),
|
||||
(datetime(2013, 10, 27, 3, 0, 0), 10800),
|
||||
(datetime(2013, 10, 27, 3, 30, 0), 10800),
|
||||
(datetime(2013, 10, 27, 3, 0, 0), 7200),
|
||||
(datetime(2013, 10, 27, 3, 30, 0), 7200),
|
||||
(datetime(2013, 10, 27, 4, 0, 0), 7200),
|
||||
(datetime(2013, 10, 27, 4, 30, 0), 7200),
|
||||
]
|
||||
|
||||
start = datetime(2013, 10, 27, 2, 0, 0)
|
||||
ct = croniter('*/30 * * * *', tz.localize(start))
|
||||
self.assertScheduleTimezone(lambda: ct.get_next(datetime), expected_schedule)
|
||||
|
||||
start = datetime(2013, 10, 27, 5, 0, 0)
|
||||
ct = croniter('*/30 * * * *', tz.localize(start))
|
||||
self.assertScheduleTimezone(lambda: ct.get_prev(datetime), reversed(expected_schedule))
|
||||
|
||||
def testTimezoneSummerTime(self):
|
||||
tz = pytz.timezone('Europe/Athens')
|
||||
|
||||
expected_schedule = [
|
||||
(datetime(2013, 3, 31, 1, 30, 0), 7200),
|
||||
(datetime(2013, 3, 31, 2, 0, 0), 7200),
|
||||
(datetime(2013, 3, 31, 2, 30, 0), 7200),
|
||||
(datetime(2013, 3, 31, 4, 0, 0), 10800),
|
||||
(datetime(2013, 3, 31, 4, 30, 0), 10800),
|
||||
]
|
||||
|
||||
start = datetime(2013, 3, 31, 1, 0, 0)
|
||||
ct = croniter('*/30 * * * *', tz.localize(start))
|
||||
self.assertScheduleTimezone(lambda: ct.get_next(datetime), expected_schedule)
|
||||
|
||||
start = datetime(2013, 3, 31, 5, 0, 0)
|
||||
ct = croniter('*/30 * * * *', tz.localize(start))
|
||||
self.assertScheduleTimezone(lambda: ct.get_prev(datetime), reversed(expected_schedule))
|
||||
|
||||
def test_std_dst(self):
|
||||
"""
|
||||
DST tests
|
||||
|
||||
This fixes https://github.com/taichino/croniter/issues/82
|
||||
|
||||
"""
|
||||
tz = pytz.timezone('Europe/Warsaw')
|
||||
# -> 2017-03-26 01:59+1:00 -> 03:00+2:00
|
||||
local_date = tz.localize(datetime(2017, 3, 26))
|
||||
val = croniter('0 0 * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 3, 27)))
|
||||
#
|
||||
local_date = tz.localize(datetime(2017, 3, 26, 1))
|
||||
cr = croniter('0 * * * *', local_date)
|
||||
val = cr.get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 3, 26, 3)))
|
||||
val = cr.get_current(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 3, 26, 3)))
|
||||
|
||||
# -> 2017-10-29 02:59+2:00 -> 02:00+1:00
|
||||
local_date = tz.localize(datetime(2017, 10, 29))
|
||||
val = croniter('0 0 * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 10, 30)))
|
||||
local_date = tz.localize(datetime(2017, 10, 29, 1, 59))
|
||||
val = croniter('0 * * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(
|
||||
val.replace(tzinfo=None),
|
||||
tz.localize(datetime(2017, 10, 29, 2)).replace(tzinfo=None))
|
||||
local_date = tz.localize(datetime(2017, 10, 29, 2))
|
||||
val = croniter('0 * * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 10, 29, 3)))
|
||||
local_date = tz.localize(datetime(2017, 10, 29, 3))
|
||||
val = croniter('0 * * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 10, 29, 4)))
|
||||
local_date = tz.localize(datetime(2017, 10, 29, 4))
|
||||
val = croniter('0 * * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 10, 29, 5)))
|
||||
local_date = tz.localize(datetime(2017, 10, 29, 5))
|
||||
val = croniter('0 * * * *', local_date).get_next(datetime)
|
||||
self.assertEqual(val, tz.localize(datetime(2017, 10, 29, 6)))
|
||||
|
||||
def test_std_dst2(self):
|
||||
"""
|
||||
DST tests
|
||||
|
||||
This fixes https://github.com/taichino/croniter/issues/87
|
||||
|
||||
São Paulo, Brazil: 18/02/2018 00:00 -> 17/02/2018 23:00
|
||||
|
||||
"""
|
||||
tz = pytz.timezone("America/Sao_Paulo")
|
||||
local_dates = [
|
||||
# 17-22: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 21, 0, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 17-23: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 22, 0, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 17-23: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 23, 0, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 18-00: 00 -> 19-00:00
|
||||
(tz.localize(datetime(2018, 2, 18, 0, 0, 0)),
|
||||
'2018-02-19 00:00:00-03:00'),
|
||||
# 17-22: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 21, 5, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 17-23: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 22, 5, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 17-23: 00 -> 18-00:00
|
||||
(tz.localize(datetime(2018, 2, 17, 23, 5, 0)),
|
||||
'2018-02-18 00:00:00-03:00'),
|
||||
# 18-00: 00 -> 19-00:00
|
||||
(tz.localize(datetime(2018, 2, 18, 0, 5, 0)),
|
||||
'2018-02-19 00:00:00-03:00'),
|
||||
]
|
||||
ret1 = [croniter("0 0 * * *", d[0]).get_next(datetime)
|
||||
for d in local_dates]
|
||||
sret1 = ['{0}'.format(d) for d in ret1]
|
||||
lret1 = ['{0}'.format(d[1]) for d in local_dates]
|
||||
self.assertEqual(sret1, lret1)
|
||||
|
||||
def test_error_alpha_cron(self):
|
||||
self.assertRaises(CroniterNotAlphaError, croniter.expand,
|
||||
'* * * janu-jun *')
|
||||
|
||||
def test_error_bad_cron(self):
|
||||
self.assertRaises(CroniterBadCronError, croniter.expand,
|
||||
'* * * *')
|
||||
self.assertRaises(CroniterBadCronError, croniter.expand,
|
||||
'* * * * * * *')
|
||||
|
||||
def test_is_valid(self):
|
||||
self.assertTrue(croniter.is_valid('0 * * * *'))
|
||||
self.assertFalse(croniter.is_valid('0 * *'))
|
||||
self.assertFalse(croniter.is_valid('* * * janu-jun *'))
|
||||
|
||||
def test_exactly_the_same_minute(self):
|
||||
base = datetime(2018, 3, 5, 12, 30, 50)
|
||||
itr = croniter('30 7,12,17 * * *', base)
|
||||
n1 = itr.get_prev(datetime)
|
||||
self.assertEqual(12, n1.hour)
|
||||
|
||||
n2 = itr.get_prev(datetime)
|
||||
self.assertEqual(7, n2.hour)
|
||||
|
||||
n3 = itr.get_next(datetime)
|
||||
self.assertEqual(12, n3.hour)
|
||||
|
||||
def test_next_when_now_satisfies_cron(self):
|
||||
ts_a = datetime(2018, 5, 21, 0, 3, 0)
|
||||
ts_b = datetime(2018, 5, 21, 0, 4, 20)
|
||||
test_cron = '4 * * * *'
|
||||
|
||||
next_a = croniter(test_cron, start_time=ts_a).get_next()
|
||||
next_b = croniter(test_cron, start_time=ts_b).get_next()
|
||||
|
||||
self.assertTrue(next_b > next_a)
|
||||
|
||||
def test_milliseconds(self):
|
||||
"""
|
||||
https://github.com/taichino/croniter/issues/107
|
||||
"""
|
||||
#
|
||||
dt = datetime(2018, 1, 2, 10, 0, 0, 500)
|
||||
c = croniter("0 10 * * * ", start_time=dt)
|
||||
ts = "{0}".format(datetime.utcfromtimestamp(c.get_prev()))
|
||||
self.assertEqual(ts, '2018-01-02 10:00:00')
|
||||
#
|
||||
dt = datetime(2018, 1, 2, 10, 0, 1, 0)
|
||||
c = croniter("0 10 * * * ", start_time=dt)
|
||||
ts = "{0}".format(datetime.utcfromtimestamp(c.get_prev()))
|
||||
self.assertEqual(ts, '2018-01-02 10:00:00')
|
||||
#
|
||||
dt = datetime(2018, 1, 2, 9, 59, 59, 999999)
|
||||
c = croniter("0 10 * * * ", start_time=dt)
|
||||
ts = "{0}".format(datetime.utcfromtimestamp(c.get_prev()))
|
||||
self.assertEqual(ts, '2018-01-01 10:00:00')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
from datetime import datetime
|
||||
from croniter import croniter
|
||||
|
||||
from croniter.tests import base
|
||||
|
||||
|
||||
class timerTest(object):
|
||||
def __init__(self):
|
||||
self.tests = tuple(getattr(self, m)
|
||||
for m in dir(self)
|
||||
if m.lower().startswith('test'))
|
||||
|
||||
def run(self):
|
||||
for test in self.tests:
|
||||
test()
|
||||
|
||||
|
||||
class CroniterTest(timerTest):
|
||||
def testMinute(self):
|
||||
# minute asterisk
|
||||
base = datetime(2010, 1, 23, 12, 18)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
n1 = itr.get_next(datetime) # 19
|
||||
base.year == n1.year
|
||||
base.month == n1.month
|
||||
base.day == n1.day
|
||||
base.hour == n1.hour
|
||||
base.minute == n1.minute - 1
|
||||
for i in range(39): # ~ 58
|
||||
itr.get_next()
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.minute == 59
|
||||
|
||||
n3 = itr.get_next(datetime)
|
||||
|
||||
n3.minute == 0
|
||||
n3.hour == 13
|
||||
|
||||
itr = croniter('*/5 * * * *', base)
|
||||
n4 = itr.get_next(datetime)
|
||||
n4.minute == 20
|
||||
for i in range(6):
|
||||
itr.get_next()
|
||||
n5 = itr.get_next(datetime)
|
||||
n5.minute == 55
|
||||
|
||||
n6 = itr.get_next(datetime)
|
||||
n6.minute == 0
|
||||
n6.hour == 13
|
||||
|
||||
def testHour(self):
|
||||
base = datetime(2010, 1, 24, 12, 2)
|
||||
itr = croniter('0 */3 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
|
||||
n1.hour == 15
|
||||
n1.minute == 0
|
||||
|
||||
for i in range(2):
|
||||
itr.get_next()
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.hour == 0
|
||||
n2.day == 25
|
||||
|
||||
def testDay(self):
|
||||
base = datetime(2010, 2, 24, 12, 9)
|
||||
itr = croniter('0 0 */3 * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n1.day == 27
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.day == 3
|
||||
|
||||
# test leap year
|
||||
base = datetime(1996, 2, 27)
|
||||
itr = croniter('0 0 * * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n1.day == 28
|
||||
n1.month == 2
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.day == 29
|
||||
n2.month == 2
|
||||
|
||||
base2 = datetime(2000, 2, 27)
|
||||
itr2 = croniter('0 0 * * *', base2)
|
||||
n3 = itr2.get_next(datetime)
|
||||
n3.day == 28
|
||||
n3.month == 2
|
||||
n4 = itr2.get_next(datetime)
|
||||
n4.day == 29
|
||||
n4.month == 2
|
||||
|
||||
def testWeekDay(self):
|
||||
base = datetime(2010, 2, 25)
|
||||
itr = croniter('0 0 * * sat', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n1.isoweekday() == 6
|
||||
n1.day == 27
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.isoweekday() == 6
|
||||
n2.day == 6
|
||||
n2.month == 3
|
||||
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 1 * wed', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n1.month == 1
|
||||
n1.day == 27
|
||||
n1.year == 2010
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.month == 2
|
||||
n2.day == 1
|
||||
n2.year == 2010
|
||||
|
||||
n3 = itr.get_next(datetime)
|
||||
n3.month == 2
|
||||
n3.day == 3
|
||||
n3.year == 2010
|
||||
|
||||
def testMonth(self):
|
||||
base = datetime(2010, 1, 25)
|
||||
itr = croniter('0 0 1 * *', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
|
||||
n1.month == 2
|
||||
n1.day == 1
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.month == 3
|
||||
n2.day == 1
|
||||
|
||||
for i in range(8):
|
||||
itr.get_next()
|
||||
|
||||
n3 = itr.get_next(datetime)
|
||||
n3.month == 12
|
||||
n3.year == 2010
|
||||
|
||||
n4 = itr.get_next(datetime)
|
||||
n4.month == 1
|
||||
n4.year == 2011
|
||||
|
||||
def testPrevMinute(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
base.year == prev.year
|
||||
base.month == prev.month
|
||||
base.day == prev.day
|
||||
base.hour == prev.hour
|
||||
base.minute, prev.minute + 1
|
||||
|
||||
base = datetime(2010, 8, 25, 15, 0)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
base.year == prev.year
|
||||
base.month == prev.month
|
||||
base.day == prev.day
|
||||
base.hour == prev.hour + 1
|
||||
59 == prev.minute
|
||||
|
||||
base = datetime(2010, 8, 25, 0, 0)
|
||||
itr = croniter('*/1 * * * *', base)
|
||||
prev = itr.get_prev(datetime)
|
||||
base.year == prev.year
|
||||
base.month == prev.month
|
||||
base.day == prev.day + 1
|
||||
23 == prev.hour
|
||||
59 == prev.minute
|
||||
|
||||
def testPrevWeekDay(self):
|
||||
base = datetime(2010, 8, 25, 15, 56)
|
||||
itr = croniter('0 0 * * sat,sun', base)
|
||||
prev1 = itr.get_prev(datetime)
|
||||
prev1.year == base.year
|
||||
prev1.month == base.month
|
||||
prev1.day == 22
|
||||
prev1.hour == 0
|
||||
prev1.minute == 0
|
||||
|
||||
prev2 = itr.get_prev(datetime)
|
||||
prev2.year == base.year
|
||||
prev2.month == base.month
|
||||
prev2.day == 21
|
||||
prev2.hour == 0
|
||||
prev2.minute == 0
|
||||
|
||||
prev3 = itr.get_prev(datetime)
|
||||
prev3.year == base.year
|
||||
prev3.month == base.month
|
||||
prev3.day == 15
|
||||
prev3.hour == 0
|
||||
prev3.minute == 0
|
||||
|
||||
def testISOWeekday(self):
|
||||
base = datetime(2010, 2, 25)
|
||||
itr = croniter('0 0 * * 7', base)
|
||||
n1 = itr.get_next(datetime)
|
||||
n1.isoweekday() == 7
|
||||
n1.day == 28
|
||||
|
||||
n2 = itr.get_next(datetime)
|
||||
n2.isoweekday() == 7
|
||||
n2.day == 7
|
||||
n2.month == 3
|
||||
|
||||
|
||||
class TestCase(base.TestCase):
|
||||
"""make zope.testrunner happy"""
|
||||
|
||||
def test_Noop(self):
|
||||
self.assertEqual(1, 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from timeit import Timer
|
||||
t = Timer('c=CroniterTest();c.run()', 'from __main__ import CroniterTest')
|
||||
print(t.timeit(200))
|
||||
Reference in New Issue
Block a user