Hello community,
here is the log from the commit of package python-croniter for openSUSE:Factory
checked in at 2020-07-17 20:51:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-croniter (Old)
and /work/SRC/openSUSE:Factory/.python-croniter.new.3592 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-croniter"
Fri Jul 17 20:51:04 2020 rev:13 rq:821436 version:0.3.34
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-croniter/python-croniter.changes
2020-06-10 00:47:28.638797561 +0200
+++
/work/SRC/openSUSE:Factory/.python-croniter.new.3592/python-croniter.changes
2020-07-17 20:51:49.208981002 +0200
@@ -1,0 +2,9 @@
+Fri Jul 17 07:25:05 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 0.3.34:
+ - Feat croniter_range(start, stop, cron)
+ - Optimization for poorly written cron expression
+ - Make dateutil tz support more official
+ - Feat/support for day or
+
+-------------------------------------------------------------------
Old:
----
croniter-0.3.32.tar.gz
New:
----
croniter-0.3.34.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-croniter.spec ++++++
--- /var/tmp/diff_new_pack.wpQvLS/_old 2020-07-17 20:51:50.368982211 +0200
+++ /var/tmp/diff_new_pack.wpQvLS/_new 2020-07-17 20:51:50.372982216 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-croniter
-Version: 0.3.32
+Version: 0.3.34
Release: 0
Summary: Python iterators for datetime objects with cron-like format
License: MIT
++++++ croniter-0.3.32.tar.gz -> croniter-0.3.34.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/PKG-INFO new/croniter-0.3.34/PKG-INFO
--- old/croniter-0.3.32/PKG-INFO 2020-05-27 18:01:44.000000000 +0200
+++ new/croniter-0.3.34/PKG-INFO 2020-06-19 15:28:16.774030200 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: croniter
-Version: 0.3.32
+Version: 0.3.34
Summary: croniter provides iteration for datetime object with cron like format
Home-page: http://github.com/kiorky/croniter
Author: Matsumoto Taichi, kiorky
@@ -98,11 +98,23 @@
About DST
=========
- Be sure to init your croniter instance with a TZ aware datetime for
this to work !::
+ Be sure to init your croniter instance with a TZ aware datetime for
this to work!
+ Example using pytz::
+
+ >>> import pytz
+ >>> tz = pytz.timezone("Europe/Paris")
>>> local_date = tz.localize(datetime(2017, 3, 26))
>>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+ Example using python_dateutil::
+
+ >>> import dateutil.tz
+ >>> tz = dateutil.tz.gettz('Asia/Tokyo')
+ >>> local_date = datetime(2017, 3, 26, tzinfo=tz)
+ >>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+
+
About second repeats
=====================
Croniter is able to do second repeatition crontabs form::
@@ -114,18 +126,35 @@
>>> itr.get_next(datetime) # 4/6 13:26:25
>>> itr.get_next(datetime) # 4/6 13:27:15
- You can also note that this expression will repeat every second from
the start datetime.
+ You can also note that this expression will repeat every second from
the start datetime.::
>>> croniter('* * * * * *', local_date).get_next(datetime)
Testing if a date matchs a crontab
==================================
- As simple as::
-
+ Test for a match with (>=0.3.32)::
+
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 0, 0, 0))
True
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 2, 0, 0))
False
+ >>>
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0,
0)) # 04:02 on every Wednesday OR on 1st day of month
+ True
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0,
0), day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
+ False
+
+
+ Iterating over a range using cron
+ =================================
+ Finding all matching times in at time range can be handled with the
``croniter_range()`` function. This is much like the builtin
``range(start,stop,step)`` function, but for dates using a cron expression as
"step".
+ Added in (>=0.3.34)
+
+ List the first Saturday of every month in 2019::
+
+ >>> from croniter import croniter_range
+ >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019,
12, 31), "0 0 * * sat#1"):
+ >>> print(dt)
Develop this package
====================
@@ -173,6 +202,22 @@
Changelog
==============
+ 0.3.34 (2020-06-19)
+ -------------------
+
+ - Feat croniter_range(start, stop, cron)
+ [Kintyr]
+ - Optimization for poorly written cron expression
+ [Kintyr]
+
+ 0.3.33 (2020-06-15)
+ -------------------
+
+ - Make dateutil tz support more official
+ [lowell80]
+ - Feat/support for day or
+ [田口信元]
+
0.3.32 (2020-05-27)
-------------------
@@ -223,7 +268,7 @@
0.3.23 (2018-05-23)
-------------------
- - fix `get_next` while perserving the fix of `get_prev` in 7661c2aaa
+ - fix ``get_next`` while perserving the fix of ``get_prev`` in
7661c2aaa
[Avikam Agur <[email protected]>]
@@ -231,7 +276,7 @@
-------------------
- Don't count previous minute if now is dynamic
If the code is triggered from 5-asterisk based cron
- `get_prev` based on `datetime.now()` is expected to return
+ ``get_prev`` based on ``datetime.now()`` is expected to return
current cron iteration and not previous execution.
[Igor Khrol <[email protected]>]
@@ -341,7 +386,7 @@
------------------
- Fix default behavior when no start_time given
- Default value for `start_time` parameter is calculated at module
init time rather than call time.
+ Default value for ``start_time`` parameter is calculated at module
init time rather than call time.
- Fix timezone support and stop depending on the system time zone
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/README.rst
new/croniter-0.3.34/README.rst
--- old/croniter-0.3.32/README.rst 2020-05-27 18:01:43.000000000 +0200
+++ new/croniter-0.3.34/README.rst 2020-06-19 15:28:16.000000000 +0200
@@ -90,11 +90,23 @@
About DST
=========
-Be sure to init your croniter instance with a TZ aware datetime for this to
work !::
+Be sure to init your croniter instance with a TZ aware datetime for this to
work!
+Example using pytz::
+
+ >>> import pytz
+ >>> tz = pytz.timezone("Europe/Paris")
>>> local_date = tz.localize(datetime(2017, 3, 26))
>>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+Example using python_dateutil::
+
+ >>> import dateutil.tz
+ >>> tz = dateutil.tz.gettz('Asia/Tokyo')
+ >>> local_date = datetime(2017, 3, 26, tzinfo=tz)
+ >>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+
+
About second repeats
=====================
Croniter is able to do second repeatition crontabs form::
@@ -106,18 +118,35 @@
>>> itr.get_next(datetime) # 4/6 13:26:25
>>> itr.get_next(datetime) # 4/6 13:27:15
-You can also note that this expression will repeat every second from the start
datetime.
+You can also note that this expression will repeat every second from the start
datetime.::
>>> croniter('* * * * * *', local_date).get_next(datetime)
Testing if a date matchs a crontab
==================================
-As simple as::
-
+Test for a match with (>=0.3.32)::
+
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 0, 0, 0))
True
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 2, 0, 0))
False
+ >>>
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0, 0)) #
04:02 on every Wednesday OR on 1st day of month
+ True
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0, 0),
day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
+ False
+
+
+Iterating over a range using cron
+=================================
+Finding all matching times in at time range can be handled with the
``croniter_range()`` function. This is much like the builtin
``range(start,stop,step)`` function, but for dates using a cron expression as
"step".
+Added in (>=0.3.34)
+
+List the first Saturday of every month in 2019::
+
+ >>> from croniter import croniter_range
+ >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019, 12, 31),
"0 0 * * sat#1"):
+ >>> print(dt)
Develop this package
====================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/docs/CHANGES.rst
new/croniter-0.3.34/docs/CHANGES.rst
--- old/croniter-0.3.32/docs/CHANGES.rst 2020-05-27 18:01:43.000000000
+0200
+++ new/croniter-0.3.34/docs/CHANGES.rst 2020-06-19 15:28:16.000000000
+0200
@@ -1,6 +1,22 @@
Changelog
==============
+0.3.34 (2020-06-19)
+-------------------
+
+- Feat croniter_range(start, stop, cron)
+ [Kintyr]
+- Optimization for poorly written cron expression
+ [Kintyr]
+
+0.3.33 (2020-06-15)
+-------------------
+
+- Make dateutil tz support more official
+ [lowell80]
+- Feat/support for day or
+ [田口信元]
+
0.3.32 (2020-05-27)
-------------------
@@ -51,7 +67,7 @@
0.3.23 (2018-05-23)
-------------------
-- fix `get_next` while perserving the fix of `get_prev` in 7661c2aaa
+- fix ``get_next`` while perserving the fix of ``get_prev`` in 7661c2aaa
[Avikam Agur <[email protected]>]
@@ -59,7 +75,7 @@
-------------------
- Don't count previous minute if now is dynamic
If the code is triggered from 5-asterisk based cron
- `get_prev` based on `datetime.now()` is expected to return
+ ``get_prev`` based on ``datetime.now()`` is expected to return
current cron iteration and not previous execution.
[Igor Khrol <[email protected]>]
@@ -169,7 +185,7 @@
------------------
- Fix default behavior when no start_time given
- Default value for `start_time` parameter is calculated at module init time
rather than call time.
+ Default value for ``start_time`` parameter is calculated at module init time
rather than call time.
- Fix timezone support and stop depending on the system time zone
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/setup.py new/croniter-0.3.34/setup.py
--- old/croniter-0.3.32/setup.py 2020-05-27 18:01:43.000000000 +0200
+++ new/croniter-0.3.34/setup.py 2020-06-19 15:28:16.000000000 +0200
@@ -23,7 +23,7 @@
setup(
name='croniter',
- version='0.3.32',
+ version='0.3.34',
py_modules=['croniter', ],
description=(
'croniter provides iteration for datetime '
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/src/croniter/__init__.py
new/croniter-0.3.34/src/croniter/__init__.py
--- old/croniter-0.3.32/src/croniter/__init__.py 2020-05-27
18:01:43.000000000 +0200
+++ new/croniter-0.3.34/src/croniter/__init__.py 2020-06-19
15:28:16.000000000 +0200
@@ -2,6 +2,7 @@
from __future__ import absolute_import
from .croniter import (
croniter,
+ croniter_range,
CroniterBadDateError, # noqa
CroniterBadCronError, # noqa
CroniterNotAlphaError # noqa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/src/croniter/croniter.py
new/croniter-0.3.34/src/croniter/croniter.py
--- old/croniter-0.3.32/src/croniter/croniter.py 2020-05-27
18:01:43.000000000 +0200
+++ new/croniter-0.3.34/src/croniter/croniter.py 2020-06-19
15:28:16.000000000 +0200
@@ -69,6 +69,15 @@
{},
)
+ LEN_MEANS_ALL = (
+ 60,
+ 24,
+ 31,
+ 12,
+ 7,
+ 60
+ )
+
bad_length = 'Exactly 5 or 6 columns has to be specified for iterator' \
'expression.'
@@ -569,7 +578,11 @@
nth_weekday_of_month[t] = set()
nth_weekday_of_month[t].add(int(nth))
+ res = set(res)
res = natsort.natsorted(res)
+ if len(res) == cls.LEN_MEANS_ALL[i]:
+ res = ['*']
+
expanded.append(['*'] if (len(res) == 1
and res[0] == '*')
else res)
@@ -586,9 +599,55 @@
return True
@classmethod
- def match(cls, cron_expression, testdate):
- cron = cls(cron_expression, testdate, ret_type=datetime.datetime)
+ def match(cls, cron_expression, testdate, day_or=True):
+ cron = cls(cron_expression, testdate, ret_type=datetime.datetime,
day_or=day_or)
td, ms1 = cron.get_current(datetime.datetime),
relativedelta(microseconds=1)
cron.set_current(td + ms1)
tdp, tdt = cron.get_current(), cron.get_prev()
return (max(tdp, tdt) - min(tdp, tdt)).total_seconds() < 60
+
+
+def croniter_range(start, stop, expr_format, ret_type=None, day_or=True,
exclude_ends=False):
+ """
+ Generator that provides all times from start to stop matching the given
cron expression.
+ If the cron expression matches either 'start' and/or 'stop', those times
will be returned as
+ well unless 'exclude_ends=True' is passed.
+
+ You can think of this function as sibling to the builtin range function
for datetime objects.
+ Like range(start,stop,step), except that here 'step' is a cron expression.
+ """
+ auto_rt = datetime.datetime
+ if type(start) != type(stop):
+ raise TypeError("The start and stop must be same type. {0} != {1}".
+ format(type(start), type(stop)))
+ if isinstance(start, (float, int)):
+ start, stop = (datetime.datetime.utcfromtimestamp(t) for t in (start,
stop))
+ auto_rt = float
+ if ret_type is None:
+ ret_type = auto_rt
+ if not exclude_ends:
+ ms1 = relativedelta(microseconds=1)
+ if start < stop: # Forward (normal) time order
+ start -= ms1
+ stop += ms1
+ else: # Reverse time order
+ start += ms1
+ stop -= ms1
+ ic = croniter(expr_format, start, ret_type=datetime.datetime,
day_or=day_or)
+ # define a continue (cont) condition function and step function for the
main while loop
+ if start < stop: # Forward
+ def cont(v):
+ return v < stop
+ step = ic.get_next
+ else: # Reverse
+ def cont(v):
+ return v > stop
+ step = ic.get_prev
+
+ dt = step()
+ while cont(dt):
+ if ret_type is float:
+ yield ic.get_current(float)
+ else:
+ yield dt
+ dt = step()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/src/croniter/tests/test_croniter.py
new/croniter-0.3.34/src/croniter/tests/test_croniter.py
--- old/croniter-0.3.32/src/croniter/tests/test_croniter.py 2020-05-27
18:01:43.000000000 +0200
+++ new/croniter-0.3.34/src/croniter/tests/test_croniter.py 2020-06-19
15:28:16.000000000 +0200
@@ -6,9 +6,10 @@
from functools import partial
from time import sleep
import pytz
-from croniter import croniter, CroniterBadDateError, CroniterBadCronError,
CroniterNotAlphaError
+from croniter import croniter, croniter_range, CroniterBadDateError,
CroniterBadCronError, CroniterNotAlphaError
from croniter.tests import base
from tzlocal import get_localzone
+import dateutil.tz
class CroniterTest(base.TestCase):
@@ -298,6 +299,32 @@
self.assertEqual(22, next.hour)
self.assertEqual(30, next.minute)
+ def testOptimizeCronExpressions(self):
+ """ Non-optimal cron expressions that can be simplified."""
+ wildcard = ['*']
+ m, h, d, mon, dow, s = range(6)
+ # Test each field individually
+ self.assertEqual(croniter('0-59 0 0 0 0').expanded[m], wildcard)
+ self.assertEqual(croniter('0 0-23 0 0 0').expanded[h], wildcard)
+ self.assertEqual(croniter('0 0 0-31 0 0').expanded[d], wildcard)
+ self.assertEqual(croniter('0 0 0 1-12 0').expanded[mon], wildcard)
+ self.assertEqual(croniter('0 0 0 0 0-6').expanded[dow], wildcard)
+ self.assertEqual(croniter('0 0 0 0 1-7').expanded[dow], wildcard)
+ self.assertEqual(croniter('0 0 0 0 0 0-59').expanded[s], wildcard)
+ # Real life examples
+ self.assertEqual(croniter('30 1-12,0,10-23 15-21 * fri').expanded[h],
wildcard)
+ self.assertEqual(croniter('30 1-23,0 15-21 * fri').expanded[h],
wildcard)
+
+ def testBlockDupRanges(self):
+ """ Ensure that duplicate/overlapping ranges are squashed """
+ m, h, d, mon, dow, s = range(6)
+ self.assertEqual(croniter('* 5,5,1-6 * * *').expanded[h],
[1,2,3,4,5,6])
+ self.assertEqual(croniter('* * * * 2-3,4-5,3,3,3').expanded[dow],
[2,3,4,5])
+ self.assertEqual(croniter('* * * * * 1,5,*/20,20,15').expanded[s], [0,
1, 5, 15, 20, 40])
+ self.assertEqual(croniter('* 4,1-4,5,4 * * *').expanded[h], [1, 2, 3,
4, 5])
+ # Real life example
+ self.assertEqual(croniter('59 23 * 1
wed,fri,mon-thu,tue,tue').expanded[dow], [1,2,3,4,5])
+
def testPrevMinute(self):
base = datetime(2010, 8, 25, 15, 56)
itr = croniter('*/1 * * * *', base)
@@ -650,6 +677,13 @@
n2 = itr2.get_next(datetime)
self.assertEqual(n2.tzinfo.zone, 'Asia/Tokyo')
+ def testTimezoneDateutil(self):
+ tokyo = dateutil.tz.gettz('Asia/Tokyo')
+ base = datetime(2013, 3, 4, 12, 15, tzinfo=tokyo)
+ itr = croniter('* * * * *', base)
+ n1 = itr.get_next(datetime)
+ self.assertEqual(n1.tzinfo.tzname(n1), 'JST')
+
def testInitNoStartTime(self):
itr = croniter('* * * * *')
sleep(.01)
@@ -970,6 +1004,36 @@
"31 * * * *",
datetime(2019, 1, 14, 1, 31, 0, 0)
))
+ self.assertTrue(croniter.match(
+ "0 0 10 * wed",
+ datetime(2020, 6, 10, 0, 0, 0, 0),
+ day_or=True
+ ))
+ self.assertTrue(croniter.match(
+ "0 0 10 * fri",
+ datetime(2020, 6, 10, 0, 0, 0, 0),
+ day_or=True
+ ))
+ self.assertTrue(croniter.match(
+ "0 0 10 * fri",
+ datetime(2020, 6, 12, 0, 0, 0, 0),
+ day_or=True
+ ))
+ self.assertTrue(croniter.match(
+ "0 0 10 * wed",
+ datetime(2020, 6, 10, 0, 0, 0, 0),
+ day_or=False
+ ))
+ self.assertFalse(croniter.match(
+ "0 0 10 * fri",
+ datetime(2020, 6, 10, 0, 0, 0, 0),
+ day_or=False
+ ))
+ self.assertFalse(croniter.match(
+ "0 0 10 * fri",
+ datetime(2020, 6, 12, 0, 0, 0, 0),
+ day_or=False
+ ))
def test_dst_issue90_st31ny(self):
@@ -1018,12 +1082,106 @@
itt.get_next(datetime).isoformat(),
itt.get_next(datetime).isoformat(),
]
- self.assertEqual(ret, [
+ self.assertEqual(rett, [
'2020-03-30T02:01:00+02:00',
'2020-03-29T01:01:00+01:00',
'2020-03-28T03:01:00+01:00',
'2020-03-29T02:01:00+02:00',
'2020-03-29T03:01:00+02:00'])
+
+class CroniterRangeTest(base.TestCase):
+
+ def test_1day_step(self):
+ start = datetime(2016, 12, 2)
+ stop = datetime(2016, 12, 10)
+ fwd = list(croniter_range(start, stop, '0 0 * * *'))
+ self.assertEqual(len(fwd), 9)
+ self.assertEqual(fwd[0], start)
+ self.assertEqual(fwd[-1], stop)
+ # Test the same, but in reverse
+ rev = list(croniter_range(stop, start, '0 0 * * *'))
+ self.assertEqual(len(rev), 9)
+ # Ensure forward/reverse are a mirror image
+ rev.reverse()
+ self.assertEqual(fwd, rev)
+
+ def test_1day_step_no_ends(self):
+ # Test without ends (exclusive)
+ start = datetime(2016, 12, 2)
+ stop = datetime(2016, 12, 10)
+ fwd = list(croniter_range(start, stop, '0 0 * * *', exclude_ends=True))
+ self.assertEqual(len(fwd), 7)
+ self.assertNotEqual(fwd[0], start)
+ self.assertNotEqual(fwd[-1], stop)
+ # Test the same, but in reverse
+ rev = list(croniter_range(stop, start, '0 0 * * *', exclude_ends=True))
+ self.assertEqual(len(rev), 7)
+ self.assertNotEqual(fwd[0], stop)
+ self.assertNotEqual(fwd[-1], start)
+
+ def test_1month_step(self):
+ start = datetime(1982, 1, 1)
+ stop = datetime(1983, 12, 31)
+ res = list(croniter_range(start, stop, '0 0 1 * *'))
+ self.assertEqual(len(res), 24)
+ self.assertEqual(res[0], start)
+ self.assertEqual(res[5].day, 1)
+ self.assertEqual(res[-1], datetime(1983, 12, 1))
+
+ def test_1minute_step_float(self):
+ start = datetime(2000, 1, 1, 0, 0)
+ stop = datetime(2000, 1, 1, 0, 1)
+ res = list(croniter_range(start, stop, '* * * * *', ret_type=float))
+ self.assertEqual(len(res), 2)
+ self.assertEqual(res[0], 946684800.0)
+ self.assertEqual(res[-1] - res[0], 60)
+
+ def test_auto_ret_type(self):
+ data = [
+ (datetime(2019, 1, 1), datetime(2020, 1, 1), datetime),
+ (1552252218.0, 1591823311.0, float),
+ ]
+ for start, stop, rtype in data:
+ ret = list(croniter_range(start, stop, "0 0 * * *"))
+ self.assertIsInstance(ret[0], rtype)
+
+ def test_input_type_exceptions(self):
+ dt_start1 = datetime(2019, 1, 1)
+ dt_stop1 = datetime(2020, 1, 1)
+ f_start1 = 1552252218.0
+ f_stop1 = 1591823311.0
+ # Mix start/stop types
+ with self.assertRaises(TypeError):
+ list(croniter_range(dt_start1, f_stop1, "0 * * * *"),
ret_type=datetime)
+ with self.assertRaises(TypeError):
+ list(croniter_range(f_start1, dt_stop1, "0 * * * *"))
+
+ def test_timezone_dst(self):
+ """ Test across DST transition, which technially is a timzone change.
"""
+ tz = pytz.timezone("US/Eastern")
+ start = tz.localize(datetime(2020, 10, 30))
+ stop = tz.localize(datetime(2020, 11, 10))
+ res = list(croniter_range(start, stop, '0 0 * * *'))
+ self.assertNotEqual(res[0].tzinfo, res[-1].tzinfo)
+ self.assertEqual(len(res), 12)
+
+ def test_extra_hour_day_prio(self):
+ def datetime_tz(*args, **kw):
+ """ Defined this in another branch. single-use-version """
+ tzinfo = kw.pop("tzinfo")
+ return tzinfo.localize(datetime(*args))
+ tz = pytz.timezone("US/Eastern")
+ cron = "0 3 * * *"
+ start = datetime_tz(2020, 3, 7, tzinfo=tz)
+ end = datetime_tz(2020, 3, 11, tzinfo=tz)
+ ret = [ i.isoformat() for i in croniter_range(start, end, cron) ]
+ self.assertEqual(ret, [
+ "2020-03-07T03:00:00-05:00",
+ "2020-03-08T03:00:00-04:00",
+ "2020-03-09T03:00:00-04:00",
+ "2020-03-10T03:00:00-04:00"])
+
+
if __name__ == '__main__':
unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/src/croniter.egg-info/PKG-INFO
new/croniter-0.3.34/src/croniter.egg-info/PKG-INFO
--- old/croniter-0.3.32/src/croniter.egg-info/PKG-INFO 2020-05-27
18:01:44.000000000 +0200
+++ new/croniter-0.3.34/src/croniter.egg-info/PKG-INFO 2020-06-19
15:28:16.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: croniter
-Version: 0.3.32
+Version: 0.3.34
Summary: croniter provides iteration for datetime object with cron like format
Home-page: http://github.com/kiorky/croniter
Author: Matsumoto Taichi, kiorky
@@ -98,11 +98,23 @@
About DST
=========
- Be sure to init your croniter instance with a TZ aware datetime for
this to work !::
+ Be sure to init your croniter instance with a TZ aware datetime for
this to work!
+ Example using pytz::
+
+ >>> import pytz
+ >>> tz = pytz.timezone("Europe/Paris")
>>> local_date = tz.localize(datetime(2017, 3, 26))
>>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+ Example using python_dateutil::
+
+ >>> import dateutil.tz
+ >>> tz = dateutil.tz.gettz('Asia/Tokyo')
+ >>> local_date = datetime(2017, 3, 26, tzinfo=tz)
+ >>> val = croniter('0 0 * * *', local_date).get_next(datetime)
+
+
About second repeats
=====================
Croniter is able to do second repeatition crontabs form::
@@ -114,18 +126,35 @@
>>> itr.get_next(datetime) # 4/6 13:26:25
>>> itr.get_next(datetime) # 4/6 13:27:15
- You can also note that this expression will repeat every second from
the start datetime.
+ You can also note that this expression will repeat every second from
the start datetime.::
>>> croniter('* * * * * *', local_date).get_next(datetime)
Testing if a date matchs a crontab
==================================
- As simple as::
-
+ Test for a match with (>=0.3.32)::
+
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 0, 0, 0))
True
>>> croniter.match("0 0 * * *", datetime(2019, 1, 14, 0, 2, 0, 0))
False
+ >>>
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0,
0)) # 04:02 on every Wednesday OR on 1st day of month
+ True
+ >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0,
0), day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
+ False
+
+
+ Iterating over a range using cron
+ =================================
+ Finding all matching times in at time range can be handled with the
``croniter_range()`` function. This is much like the builtin
``range(start,stop,step)`` function, but for dates using a cron expression as
"step".
+ Added in (>=0.3.34)
+
+ List the first Saturday of every month in 2019::
+
+ >>> from croniter import croniter_range
+ >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019,
12, 31), "0 0 * * sat#1"):
+ >>> print(dt)
Develop this package
====================
@@ -173,6 +202,22 @@
Changelog
==============
+ 0.3.34 (2020-06-19)
+ -------------------
+
+ - Feat croniter_range(start, stop, cron)
+ [Kintyr]
+ - Optimization for poorly written cron expression
+ [Kintyr]
+
+ 0.3.33 (2020-06-15)
+ -------------------
+
+ - Make dateutil tz support more official
+ [lowell80]
+ - Feat/support for day or
+ [田口信元]
+
0.3.32 (2020-05-27)
-------------------
@@ -223,7 +268,7 @@
0.3.23 (2018-05-23)
-------------------
- - fix `get_next` while perserving the fix of `get_prev` in 7661c2aaa
+ - fix ``get_next`` while perserving the fix of ``get_prev`` in
7661c2aaa
[Avikam Agur <[email protected]>]
@@ -231,7 +276,7 @@
-------------------
- Don't count previous minute if now is dynamic
If the code is triggered from 5-asterisk based cron
- `get_prev` based on `datetime.now()` is expected to return
+ ``get_prev`` based on ``datetime.now()`` is expected to return
current cron iteration and not previous execution.
[Igor Khrol <[email protected]>]
@@ -341,7 +386,7 @@
------------------
- Fix default behavior when no start_time given
- Default value for `start_time` parameter is calculated at module
init time rather than call time.
+ Default value for ``start_time`` parameter is calculated at module
init time rather than call time.
- Fix timezone support and stop depending on the system time zone
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/croniter-0.3.32/src/croniter.egg-info/requires.txt
new/croniter-0.3.34/src/croniter.egg-info/requires.txt
--- old/croniter-0.3.32/src/croniter.egg-info/requires.txt 2020-05-27
18:01:44.000000000 +0200
+++ new/croniter-0.3.34/src/croniter.egg-info/requires.txt 2020-06-19
15:28:16.000000000 +0200
@@ -1,2 +1,2 @@
-python_dateutil
natsort
+python_dateutil