{"id":13494295,"url":"https://github.com/kiorky/croniter-fork","last_synced_at":"2025-03-28T13:33:00.695Z","repository":{"id":4794672,"uuid":"5947429","full_name":"kiorky/croniter-fork","owner":"kiorky","description":"croniter is a python module to provide iteration for datetime object.","archived":false,"fork":true,"pushed_at":"2021-06-25T08:19:04.000Z","size":358,"stargazers_count":224,"open_issues_count":2,"forks_count":37,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-09-27T00:26:01.775Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://github.com/taichino/croniter","language":"Python","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"taichino/croniter","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kiorky.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-09-25T09:03:50.000Z","updated_at":"2023-12-17T09:30:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kiorky/croniter-fork","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiorky%2Fcroniter-fork","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiorky%2Fcroniter-fork/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiorky%2Fcroniter-fork/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiorky%2Fcroniter-fork/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiorky","download_url":"https://codeload.github.com/kiorky/croniter-fork/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222382544,"owners_count":16975383,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:23.576Z","updated_at":"2024-10-31T08:32:13.196Z","avatar_url":"https://github.com/kiorky.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"Introduction\n============\n\n.. contents::\n\n\ncroniter provides iteration for the datetime object with a cron like format.\n\n::\n\n                          _ _\n      ___ _ __ ___  _ __ (_) |_ ___ _ __\n     / __| '__/ _ \\| '_ \\| | __/ _ \\ '__|\n    | (__| | | (_) | | | | | ||  __/ |\n     \\___|_|  \\___/|_| |_|_|\\__\\___|_|\n\n\nWebsite: https://github.com/kiorky/croniter\n\nTravis badge\n=============\n.. image:: https://travis-ci.org/kiorky/croniter.svg?branch=master\n    :target: https://travis-ci.org/kiorky/croniter\n\n\nUsage\n============\n\nA simple example::\n\n    \u003e\u003e\u003e from croniter import croniter\n    \u003e\u003e\u003e from datetime import datetime\n    \u003e\u003e\u003e base = datetime(2010, 1, 25, 4, 46)\n    \u003e\u003e\u003e iter = croniter('*/5 * * * *', base)  # every 5 minutes\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-25 04:50:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-25 04:55:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-25 05:00:00\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e iter = croniter('2 4 * * mon,fri', base)  # 04:02 on every Monday and Friday\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-26 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-30 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-02-02 04:02:00\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e iter = croniter('2 4 1 * wed', base)  # 04:02 on every Wednesday OR on 1st day of month\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-27 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-02-01 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-02-03 04:02:00\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e iter = croniter('2 4 1 * wed', base, day_or=False)  # 04:02 on every 1st day of the month if it is a Wednesday\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-09-01 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-12-01 04:02:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2011-06-01 04:02:00\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e iter = croniter('0 0 * * sat#1,sun#2', base)  # 1st Saturday, and 2nd Sunday of the month\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-02-06 00:00:00\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e iter = croniter('0 0 * * 5#3,L5', base)  # 3rd and last Friday of the month\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-01-29 00:00:00\n    \u003e\u003e\u003e print(iter.get_next(datetime))   # 2010-02-19 00:00:00\n\n\nAll you need to know is how to use the constructor and the ``get_next``\nmethod, the signature of these methods are listed below::\n\n    \u003e\u003e\u003e def __init__(self, cron_format, start_time=time.time(), day_or=True)\n\ncroniter iterates along with ``cron_format`` from ``start_time``.\n``cron_format`` is **min hour day month day_of_week**, you can refer to\nhttp://en.wikipedia.org/wiki/Cron for more details. The ``day_or``\nswitch is used to control how croniter handles **day** and **day_of_week**\nentries. Default option is the cron behaviour, which connects those\nvalues using **OR**. If the switch is set to False, the values are connected\nusing **AND**. This behaves like fcron and enables you to e.g. define a job that\nexecutes each 2nd friday of a month by setting the days of month and the\nweekday.\n::\n\n    \u003e\u003e\u003e def get_next(self, ret_type=float)\n\nget_next calculates the next value according to the cron expression and\nreturns an object of type ``ret_type``. ``ret_type`` should be a ``float`` or a\n``datetime`` object.\n\nSupported added for ``get_prev`` method. (\u003e= 0.2.0)::\n\n    \u003e\u003e\u003e base = datetime(2010, 8, 25)\n    \u003e\u003e\u003e itr = croniter('0 0 1 * *', base)\n    \u003e\u003e\u003e print(itr.get_prev(datetime))  # 2010-08-01 00:00:00\n    \u003e\u003e\u003e print(itr.get_prev(datetime))  # 2010-07-01 00:00:00\n    \u003e\u003e\u003e print(itr.get_prev(datetime))  # 2010-06-01 00:00:00\n\nYou can validate your crons using ``is_valid`` class method. (\u003e= 0.3.18)::\n\n    \u003e\u003e\u003e croniter.is_valid('0 0 1 * *')  # True\n    \u003e\u003e\u003e croniter.is_valid('0 wrong_value 1 * *')  # False\n\nAbout DST\n=========\nBe sure to init your croniter instance with a TZ aware datetime for this to work!\n\nExample using pytz::\n\n    \u003e\u003e\u003e import pytz\n    \u003e\u003e\u003e tz = pytz.timezone(\"Europe/Paris\")\n    \u003e\u003e\u003e local_date = tz.localize(datetime(2017, 3, 26))\n    \u003e\u003e\u003e val = croniter('0 0 * * *', local_date).get_next(datetime)\n\nExample using python_dateutil::\n\n    \u003e\u003e\u003e import dateutil.tz\n    \u003e\u003e\u003e tz = dateutil.tz.gettz('Asia/Tokyo')\n    \u003e\u003e\u003e local_date = datetime(2017, 3, 26, tzinfo=tz)\n    \u003e\u003e\u003e val = croniter('0 0 * * *', local_date).get_next(datetime)\n\n\nAbout second repeats\n=====================\nCroniter is able to do second repeatition crontabs form::\n\n    \u003e\u003e\u003e croniter('* * * * * 1', local_date).get_next(datetime)\n    \u003e\u003e\u003e base = datetime(2012, 4, 6, 13, 26, 10)\n    \u003e\u003e\u003e itr = croniter('* * * * * 15,25', base)\n    \u003e\u003e\u003e itr.get_next(datetime) # 4/6 13:26:15\n    \u003e\u003e\u003e itr.get_next(datetime) # 4/6 13:26:25\n    \u003e\u003e\u003e itr.get_next(datetime) # 4/6 13:27:15\n\nYou can also note that this expression will repeat every second from the start datetime.::\n\n    \u003e\u003e\u003e croniter('* * * * * *', local_date).get_next(datetime)\n\nTesting if a date matches a crontab\n===================================\nTest for a match with (\u003e=0.3.32)::\n\n    \u003e\u003e\u003e croniter.match(\"0 0 * * *\", datetime(2019, 1, 14, 0, 0, 0, 0))\n    True\n    \u003e\u003e\u003e croniter.match(\"0 0 * * *\", datetime(2019, 1, 14, 0, 2, 0, 0))\n    False\n    \u003e\u003e\u003e\n    \u003e\u003e\u003e 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\n    True\n    \u003e\u003e\u003e 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\n    False\n\nGaps between date matches\n=========================\nFor performance reasons, croniter limits the amount of CPU cycles spent attempting to find the next match.\nStarting in v0.3.35, this behavior is configurable via the ``max_years_between_matches`` parameter, and the default window has been increased from 1 year to 50 years.\n\nThe defaults should be fine for many use cases.\nApplications that evaluate multiple cron expressions or handle cron expressions from untrusted sources or end-users should use this parameter.\nIterating over sparse cron expressions can result in increased CPU consumption or a raised ``CroniterBadDateError`` exception which indicates that croniter has given up attempting to find the next (or previous) match.\nExplicitly specifying ``max_years_between_matches`` provides a way to limit CPU utilization and simplifies the iterable interface by eliminating the need for ``CroniterBadDateError``.\nThe difference in the iterable interface is based on the reasoning that whenever ``max_years_between_matches`` is explicitly agreed upon, there is no need for croniter to signal that it has given up; simply stopping the iteration is preferable.\n\nThis example matches 4 AM Friday, January 1st.\nSince January 1st isn't often a Friday, there may be a few years between each occurrence.\nSetting the limit to 15 years ensures all matches::\n\n    \u003e\u003e\u003e it = croniter(\"0 4 1 1 fri\", datetime(2000,1,1), day_or=False, max_years_between_matches=15).all_next(datetime)\n    \u003e\u003e\u003e for i in range(5):\n    ...     print(next(it))\n    ...\n    2010-01-01 04:00:00\n    2016-01-01 04:00:00\n    2021-01-01 04:00:00\n    2027-01-01 04:00:00\n    2038-01-01 04:00:00\n\nHowever, when only concerned with dates within the next 5 years, simply set ``max_years_between_matches=5`` in the above example.\nThis will result in no matches found, but no additional cycles will be wasted on unwanted matches far in the future.\n\nIterating over a range using cron\n=================================\nFind 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.\nAdded in (\u003e=0.3.34)\n\nList the first Saturday of every month in 2019::\n\n    \u003e\u003e\u003e from croniter import croniter_range\n    \u003e\u003e\u003e for dt in croniter_range(datetime(2019, 1, 1), datetime(2019, 12, 31), \"0 0 * * sat#1\"):\n    \u003e\u003e\u003e     print(dt)\n\n\nHashed expressions\n==================\n\ncroniter supports Jenkins-style hashed expressions, using the \"H\" definition keyword and the required hash_id keyword argument.\nHashed expressions remain consistent, given the same hash_id, but different hash_ids will evaluate completely different to each other.\nThis allows, for example, for an even distribution of differently-named jobs without needing to manually spread them out.\n\n    \u003e\u003e\u003e itr = croniter(\"H H * * *\", hash_id=\"hello\")\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 10, 11, 10)\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 11, 11, 10)\n    \u003e\u003e\u003e itr = croniter(\"H H * * *\", hash_id=\"hello\")\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 10, 11, 10)\n    \u003e\u003e\u003e itr = croniter(\"H H * * *\", hash_id=\"bonjour\")\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 10, 20, 52)\n\n\nRandom expressions\n==================\n\nRandom \"R\" definition keywords are supported, and remain consistent only within their croniter() instance.\n\n    \u003e\u003e\u003e itr = croniter(\"R R * * *\")\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 10, 22, 56)\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 11, 22, 56)\n    \u003e\u003e\u003e itr = croniter(\"R R * * *\")\n    \u003e\u003e\u003e itr.get_next(datetime)\n    datetime.datetime(2021, 4, 11, 4, 19)\n\n\nKeyword expressions\n===================\n\nVixie cron-style \"@\" keyword expressions are supported.\nWhat they evaluate to depends on whether you supply hash_id: no hash_id corresponds to Vixie cron definitions (exact times, minute resolution), while with hash_id corresponds to Jenkins definitions (hashed within the period, second resolution).\n\n    ============ ============ ================\n    Keyword      No hash_id   With hash_id\n    ============ ============ ================\n    @midnight    0 0 * * *    H H(0-2) * * * H\n    @hourly      0 * * * *    H * * * * H\n    @daily       0 0 * * *    H H * * * H\n    @weekly      0 0 * * 0    H H * * H H\n    @monthly     0 0 1 * *    H H H * * H\n    @yearly      0 0 1 1 *    H H H H * H\n    @annually    0 0 1 1 *    H H H H * H\n    ============ ============ ================\n\n\nDevelop this package\n====================\n\n::\n\n    git clone https://github.com/kiorky/croniter.git\n    cd croniter\n    virtualenv --no-site-packages venv\n    . venv/bin/activate\n    pip install --upgrade -r requirements/test.txt\n    py.test src\n\n\nMake a new release\n====================\nWe use zest.fullreleaser, a great release infrastructure.\n\nDo and follow these instructions\n::\n\n    . venv/bin/activate\n    pip install --upgrade -r requirements/release.txt\n    ./release.sh\n\n\nContributors\n===============\nThanks to all who have contributed to this project!\nIf you have contributed and your name is not listed below please let me know.\n\n    - mrmachine\n    - Hinnack\n    - shazow\n    - kiorky\n    - jlsandell\n    - mag009\n    - djmitche\n    - GreatCombinator\n    - chris-baynes\n    - ipartola\n    - yuzawa-san\n    - lowell80 (Kintyre)\n    - scop\n    - zed2015\n    - Ryan Finnie (rfinnie)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiorky%2Fcroniter-fork","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiorky%2Fcroniter-fork","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiorky%2Fcroniter-fork/lists"}