croniter 0.3.35


pip install croniter==0.3.35

Project Links

Meta
Author: Matsumoto Taichi, kiorky
Requires Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*

Classifiers

Development Status
  • 4 - Beta

Intended Audience
  • Developers

License
  • OSI Approved :: MIT License

Operating System
  • POSIX

Programming Language
  • Python
  • Python :: 2
  • Python :: 2.6
  • Python :: 2.7
  • Python :: 3
  • Python :: 3.4
  • Python :: 3.5
  • Python :: 3.6
  • Python :: 3.7

Topic
  • Software Development :: Libraries :: Python Modules

Introduction

croniter provides iteration for the datetime object with a cron like format.

                      _ _
  ___ _ __ ___  _ __ (_) |_ ___ _ __
 / __| '__/ _ \| '_ \| | __/ _ \ '__|
| (__| | | (_) | | | | | ||  __/ |
 \___|_|  \___/|_| |_|_|\__\___|_|

Website: https://github.com/kiorky/croniter

Travis badge

https://travis-ci.org/kiorky/croniter.svg?branch=master

Usage

A simple example:

>>> from croniter import croniter
>>> from datetime import datetime
>>> base = datetime(2010, 1, 25, 4, 46)
>>> iter = croniter('*/5 * * * *', base)  # every 5 minutes
>>> print(iter.get_next(datetime))   # 2010-01-25 04:50:00
>>> print(iter.get_next(datetime))   # 2010-01-25 04:55:00
>>> print(iter.get_next(datetime))   # 2010-01-25 05:00:00
>>>
>>> iter = croniter('2 4 * * mon,fri', base)  # 04:02 on every Monday and Friday
>>> print(iter.get_next(datetime))   # 2010-01-26 04:02:00
>>> print(iter.get_next(datetime))   # 2010-01-30 04:02:00
>>> print(iter.get_next(datetime))   # 2010-02-02 04:02:00
>>>
>>> iter = croniter('2 4 1 * wed', base)  # 04:02 on every Wednesday OR on 1st day of month
>>> print(iter.get_next(datetime))   # 2010-01-27 04:02:00
>>> print(iter.get_next(datetime))   # 2010-02-01 04:02:00
>>> print(iter.get_next(datetime))   # 2010-02-03 04:02:00
>>>
>>> iter = croniter('2 4 1 * wed', base, day_or=False)  # 04:02 on every 1st day of the month if it is a Wednesday
>>> print(iter.get_next(datetime))   # 2010-09-01 04:02:00
>>> print(iter.get_next(datetime))   # 2010-12-01 04:02:00
>>> print(iter.get_next(datetime))   # 2011-06-01 04:02:00
>>> iter = croniter('0 0 * * sat#1,sun#2', base)
>>> print(iter.get_next(datetime))   # datetime.datetime(2010, 2, 6, 0, 0)

All you need to know is how to use the constructor and the get_next method, the signature of these methods are listed below:

>>> def __init__(self, cron_format, start_time=time.time(), day_or=True)

croniter iterates along with cron_format from start_time. cron_format is min hour day month day_of_week, you can refer to http://en.wikipedia.org/wiki/Cron for more details. The day_or switch is used to control how croniter handles day and day_of_week entries. Default option is the cron behaviour, which connects those values using OR. If the switch is set to False, the values are connected using AND. This behaves like fcron and enables you to e.g. define a job that executes each 2nd friday of a month by setting the days of month and the weekday.

>>> def get_next(self, ret_type=float)

get_next calculates the next value according to the cron expression and returns an object of type ret_type. ret_type should be a float or a datetime object.

Supported added for get_prev method. (>= 0.2.0):

>>> base = datetime(2010, 8, 25)
>>> itr = croniter('0 0 1 * *', base)
>>> print(itr.get_prev(datetime))  # 2010-08-01 00:00:00
>>> print(itr.get_prev(datetime))  # 2010-07-01 00:00:00
>>> print(itr.get_prev(datetime))  # 2010-06-01 00:00:00

You can validate your crons using is_valid class method. (>= 0.3.18):

>>> croniter.is_valid('0 0 1 * *')  # True
>>> croniter.is_valid('0 wrong_value 1 * *')  # False

About DST

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:

>>> croniter('* * * * * 1', local_date).get_next(datetime)
>>> base = datetime(2012, 4, 6, 13, 26, 10)
>>> itr = croniter('* * * * * 15,25', base)
>>> itr.get_next(datetime) # 4/6 13:26:15
>>> 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.:

>>> croniter('* * * * * *', local_date).get_next(datetime)

Testing if a date matchs a crontab

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

Gaps between date matches

For performance reasons, croniter limits the amount of CPU cycles spent attempting to find the next match. By default croniter stops looking for dates more than 50 years away from the current time, and if the next cannot be reached within that span then CroniterBadDateError is raised. This works fine for most “normal” cron expressions, but can be limiting for very rare cron expressions.

For example, say you’re looking to match 4AM Friday January 1st. Since January 1 isn’t often a Friday, it can be a few years between each occurrence. Starting in v0.3.35, croniter provides a max_years_between_matches parameter that allows more than 50 years default to be extended for scenarios like this:

>>> it = croniter("0 4 1 1 fri", datetime(2000,1,1), day_or=False, max_years_between_matches=100).all_next(datetime)
>>> for i in range(5):
...     print(next(it))
...
2010-01-01 04:00:00
2016-01-01 04:00:00
2021-01-01 04:00:00
2027-01-01 04:00:00
2038-01-01 04:00:00

Trying this without max_years_between_matches results in an exception, because there’s a full decade between the 2000 start date and the first match in 2010:

>>> it = croniter("0 4 1 1 fri", datetime(2000,1,1), day_or=False).all_next()
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
croniter.CroniterBadDateError: failed to find next date

One advantage of explicitly specifying max_years_between_matches is that it simplifies the various iterable interfaces. Specifically all_next(), all_prev() and iter()) stop raising the CroniterBadDateError exception when a window is specified. The rationale is that since you’ve explicitly told croniter how far to look into the future (or past) to find the next/previous date, there’s no need for a special exception. Instead, if no match is found then iteration is stopped. This makes the these iterable interfaces act as more like normal Python iterators without having to deal with any extra exceptions. This distinction allows v0.3.35 and later to keep the same default behavior as earlier versions.

In summary: For many cron expressions this will never matter. Use max_years_between_matches to make iteration simplier.

Iterating over a range using cron

Find matches within a range using the croniter_range() function. This is much like the builtin range(start,stop,step) function, but for dates. The step argument is a cron expression. 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

git clone https://github.com/kiorky/croniter.git
cd croniter
virtualenv --no-site-packages venv
. venv/bin/activate
pip install --upgrade -r requirements/test.txt
py.test src

Make a new release

We use zest.fullreleaser, a great release infrastructure.

Do and follow these instructions

. venv/bin/activate
pip install --upgrade -r requirements/release.txt
./release.sh

Contributors

Thanks to all who have contributed to this project! If you have contributed and your name is not listed below please let me know.

  • mrmachine

  • Hinnack

  • shazow

  • kiorky

  • jlsandell

  • mag009

  • djmitche

  • GreatCombinator

  • chris-baynes

  • ipartola

  • yuzawa-san

  • lowell80

Changelog

0.3.35 (2020-10-11)

  • Handle L in ranges. This fixes #142. [kiorky]

  • Add a new initializaton paramter max_years_between_matches to support finding the next/previous date beyond the default 1 year window, if so desired. Updated README to include additional notes and example of this usage. Fixes #145. [Kintyre]

  • The croniter_range() function was updated to automatically determines the appropriate max_years_between_matches value, this preventing handling of the CroniterBadDateError exception. [Kintyre]

  • Updated exception handling classes: CroniterBadDateError now only applies during date finding operations (next/prev), and all parsing errors can now be caught using CroniterBadCronError. The CroniterNotAlphaError exception is now a subclass of CroniterBadCronError. A breif description of each exception class was added as an inline docstring. [Kintyre]

  • Updated iterable interfaces to replace the CroniterBadDateError with StopIteration if (and only if) the max_years_between_matches argument is provided. The rationale here is that if the user has specified the max tollernace between matches, then there’s no need to further inform them of no additional matches. Just stop the iteration. This also keeps backwards compatibility. [Kintyre]

  • Minor docs update [Kintyre]

0.3.34 (2020-06-19)

  • Feat croniter_range(start, stop, cron) [Kintyre]

  • Optimization for poorly written cron expression [Kintyre]

0.3.33 (2020-06-15)

  • Make dateutil tz support more official [lowell80]

  • Feat/support for day or [田口信元]

0.3.32 (2020-05-27)

  • document seconds repeats, fixes #122 [kiorky]

  • Implement match method, fixes #54 [kiorky]

  • Adding tests for #127 (test more DSTs and croniter behavior around) [kiorky]

  • Changed lag_hours comparison to absolute to manage dst boundary when getting previous [Sokkka]

0.3.31 (2020-01-02)

  • Fix get_next() when start_time less then 1s before next instant [AlexHill]

0.3.30 (2019-04-20)

  • credits

0.3.29 (2019-03-26)

  • credits

  • history stripping (security)

  • Handle -Sun notation, This fixes #119. [kiorky]

  • Handle invalid ranges correctly, This fixes #114. [kiorky]

0.3.25 (2018-08-07)

  • Pypi hygiene [hugovk]

0.3.24 (2018-06-20)

  • fix #107: microsecond threshold [kiorky]

0.3.23 (2018-05-23)

0.3.22 (2018-05-16)

  • 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 current cron iteration and not previous execution. [Igor Khrol <igor.khrol@toptal.com>]

0.3.20 (2017-11-06)

0.3.19 (2017-08-31)

  • fix #87: backward dst changes [kiorky]

0.3.18 (2017-08-31)

0.3.17 (2017-05-22)

0.3.16 (2017-03-15)

0.3.15 (2017-02-16)

  • fix bug around multiple conditions and range_val in _get_prev_nearest_diff. [abeja-yuki@github]

0.3.14 (2017-01-25)

  • issue #69: added day_or option to change behavior when day-of-month and day-of-week is given [Andreas Vogl <a.vogl@hackner-security.com>]

0.3.13 (2016-11-01)

0.3.12 (2016-03-10)

0.3.11 (2016-01-13)

  • Bug fix: The get_prev API crashed when last day of month token was used. Some essential logic was missing. [Iddo Aviram <iddo.aviram@similarweb.com>]

0.3.10 (2015-11-29)

  • The fuctionality of ‘l’ as day of month was broken, since the month variable was not properly updated [Iddo Aviram <iddo.aviram@similarweb.com>]

0.3.9 (2015-11-19)

  • Don’t use datetime functions python 2.6 doesn’t support [petervtzand]

0.3.8 (2015-06-23)

  • Truncate microseconds by setting to 0 [Corey Wright]

0.3.7 (2015-06-01)

  • converting sun in range sun-thu transforms to int 0 which is recognized as empty string; the solution was to convert sun to string “0”

0.3.6 (2015-05-29)

  • Fix default behavior when no start_time given 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

0.3.5 (2014-08-01)

  • support for ‘l’ (last day of month)

0.3.4 (2014-01-30)

  • Python 3 compat

  • QA Relase

0.3.3 (2012-09-29)

  • proper packaging

6.0.0 Dec 17, 2024
5.0.1 Oct 29, 2024
4.0.0 Oct 28, 2024
3.0.4 Oct 25, 2024
3.0.3 Jul 26, 2024
3.0.2 Jul 26, 2024
3.0.1 Jul 25, 2024
3.0.0 Jul 23, 2024
2.0.7 Jul 16, 2024
2.0.6 Jul 16, 2024
2.0.5 Apr 20, 2024
2.0.4 Apr 20, 2024
2.0.3 Mar 19, 2024
2.0.2 Feb 29, 2024
2.0.1 Oct 11, 2023
2.0.0 Oct 10, 2023
1.4.1 Jun 15, 2023
1.4.0 Jun 15, 2023
1.3.15 May 25, 2023
1.3.14 Apr 12, 2023
1.3.13 Apr 12, 2023
1.3.12 Apr 12, 2023
1.3.11 Apr 12, 2023
1.3.10 Apr 07, 2023
1.3.8 Nov 22, 2022
1.3.7 Sep 06, 2022
1.3.6 Sep 06, 2022
1.3.5 May 14, 2022
1.3.4 Feb 18, 2022
1.3.3 Feb 18, 2022
1.3.2 Feb 18, 2022
1.3.1 Feb 15, 2022
1.3.0 Feb 15, 2022
1.2.0 Jan 14, 2022
1.1.0 Dec 03, 2021
1.0.15 Jun 25, 2021
1.0.14 Jun 25, 2021
1.0.13 May 06, 2021
1.0.13.dev0 Apr 14, 2021
1.0.12 Apr 13, 2021
1.0.11 Apr 07, 2021
1.0.10 Mar 25, 2021
1.0.9 Mar 23, 2021
1.0.8 Mar 06, 2021
1.0.7 Mar 02, 2021
1.0.6 Feb 01, 2021
1.0.5 Jan 29, 2021
1.0.4 Jan 29, 2021
1.0.3 Jan 29, 2021
1.0.2 Jan 19, 2021
1.0.1 Jan 06, 2021
0.3.37 Dec 31, 2020
0.3.36 Nov 02, 2020
0.3.35 Oct 11, 2020
0.3.34 Jun 19, 2020
0.3.33 Jun 15, 2020
0.3.32 May 27, 2020
0.3.31 Jan 02, 2020
0.3.30 Apr 20, 2019
0.3.29 Mar 26, 2019
0.3.28 Mar 19, 2019
0.3.25 Aug 07, 2018
0.3.24 Jun 20, 2018
0.3.23 May 23, 2018
0.3.22 May 16, 2018
0.3.20 Nov 06, 2017
0.3.19 Aug 31, 2017
0.3.18 Aug 31, 2017
0.3.17 May 22, 2017
0.3.16 Mar 15, 2017
0.3.15 Feb 16, 2017
0.3.14 Jan 25, 2017
0.3.13 Nov 01, 2016
0.3.12 Mar 10, 2016
0.3.11 Jan 13, 2016
0.3.10 Nov 29, 2015
0.3.9 Nov 19, 2015
0.3.8 Jun 23, 2015
0.3.7 Jun 01, 2015
0.3.6 May 29, 2015
0.3.5 Aug 01, 2014
0.3.4 Jan 29, 2014
0.3.3 Sep 29, 2012
0.3.2 Sep 26, 2012
0.3.1 Sep 26, 2012
0.3.0 Apr 06, 2012
0.2.7 Feb 24, 2012
0.2.5 Jan 27, 2011
0.2.4 Jan 26, 2011
0.2.2 Jan 26, 2011
0.2.0 Aug 25, 2010
0.1.6 Aug 10, 2010
0.1.5 Jan 27, 2010
0.1.4 Jan 27, 2010
0.1.3 Jan 24, 2010
0.1.2 Jan 24, 2010
0.1.1 Jan 24, 2010
0.0rc0 Jan 27, 2010

Wheel compatibility matrix

Platform Python 2 Python 3
any

Files in release

Extras: None
Dependencies:
natsort
python-dateutil