# ChronoX
> The project details and documentation can be found [here](https://chronox-doc.vercel.app/); It also provides a online API (coming soon) with rust implementation;
**ChronoX** is a project to extend the functionalities of conventional [cron](https://en.wikipedia.org/wiki/Cron) utility;
It provides more expressive power (day of year, month of week, span of time) by using expression (let's call it **cronx**) similar to the conventional one;
Besides conventional next/prev 1 search, **ChronoX** provides convinient function to directly and efficiently compute the next/prev `n` occurence of desired pattern,
where `n` could be extremely large! Most conventional implementation requires looping which leads to a *O*(n) time complexity, whereas **ChronoX** utilizes optimized algorithm to reduce the time complexity down to somewhere between **constant** and **log** between **ChronoX** rust implementation and a popular rust crate;
If you needs to express the following besides the conventional cron:
- day of year
- week of month
- time span between start and end
or, you needs to compute time **`N`** leaps away,
**ChronoX** would be your right choice!
This is a python implementation of **ChronoX**. It requires using **cronx**, a cron like expression, see [cronx guide below](#cronx) or detail docs.
### Install
```bash
pip install chronox-python
```
> python >= 3.8
### Usage
This package provides two main classes: `ChronoX` for time point and `ChronoXSpan` for time span.
The input and output should be encapsulated by `datetime` class from `datetime` module;
```python
from datetime import datetime
```
#### Time Point
`ChronoX` class provides 3 main functions: `prev` and `next` to calculate previous and next time point respectively and `contains` to check if the passed in datetime can be represented by the pattern.
```python
from chronox import ChronoX
from datetime import datetime
cron = ChronoX("* * * 1,3,5 * * ; c")
assert cron.prev(datetime(2003, 11, 10, 6, 0, 6)) == datetime(2003, 11, 10, 6, 0, 5)
assert cron.prev(datetime(2003, 11, 10, 6, 0, 6), 1) == datetime(2003, 11, 10, 6, 0, 5)
assert cron.prev(datetime(2003, 11, 10, 6, 0, 6), leap=1) == datetime(2003, 11, 10, 6, 0, 5)
assert cron.prev(datetime(2003, 11, 10, 6, 0, 6), leap=10) == datetime(2003, 11, 9, 5, 59, 50)
assert cron.next(datetime(2003, 11, 10, 5, 59, 59)) == datetime(2003, 11, 11, 1, 0, 0)
# If current datetime represented by the cron
cron.contains(datetime.now())
# is equivalent to
datetime.now() in cron
```
parameter for datetime is optional and default to datetime.now()
#### Time Span
`ChronoXSpan` provides a main function `contains`. It also provide `start` and `end` properties which reference decoded ChronoX instance for start and end pattern, you can utilize these two properties for calculation releted start or end pattern seperately.
```python
from chronox import ChronoXSpan
from datetime import datetime
period = ChronoXSpan("* 1,3,5 * 3..5 0 0 0; m")
assert period.contains(datetime(2003, 5, 16, 0, 0, 0))
# is equivalent to
datetime(2003, 5, 16, 0, 0, 0).now() in cron
# calculate next start time
period.start.next()
# calculate next end time
period.end.next()
```
# cronx
This guide explains **cronx** expression by comparing it with conventional cron;
if you are unfamiliar with cron, please read about [cron](https://en.wikipedia.org/wiki/Cron) first, or go to [detail](https://chronox-doc.vercel.app/cronx/detail) explaination directly.
### More Expressive
Beyond all the time pattern a conventional cron support, **cronx** also support the following pattern:
1. `day of year`
2. `week of month`
3. `span of time` from `start time pattern` to `end time pattern`
All week date definition follows ISO standard, see [details](https://en.wikipedia.org/wiki/ISO_week_date)
In order to support these extra time patterns, **cronx** introduces the following main differences from the conventional cron:
1. explicit indicator calendar mode
2. different order of unit expression
3. new character set `..` for span of time
Let's go through them one by one.
### Calendar Mode and Indicator
>full # of units include three clock units: `hour`, `minute`, `second`
| Token | Description | Calendar Combination | full # of units |
| -------| ----------- | -------------------- | --------------- |
| `d` | day of year | `year`, `day of year` | 5 |
| `w` | week of year | `year`, `week of year`, `day of week` | 6 |
| `m` | special month special month composed by week | `year`, `month`, `week of month`, `day of week` | 7 |
| `c` | common mode | `year`, `month`, `day of month` | 6 |
All indicator tokens should be append to the end of expression string, and using `;` to seperate from main expression.
### Order of Unit
Generally, **cronx** takes a reverse order compared to cron, that is from bigger unit to smaller one
| mode | Order |
| -------| ----------- |
| `d` | `year` `day of year` `hour` `minute` `second` |
| `w` | `year` `week of year` `day of week` `hour` `minute` `second` |
| `m` | `year` `month` `week of month` `day of week` `hour` `minute` `second` |
| `c` | `year` `month` `day of month` `hour` `minute` `second` |
### Span of Time
This is a new concept, it represents a span or a block of time from a start to an end expressed by **cronx**, start and end occur in pairs, and connected by new character set `..` in **cronx**.
| cronx | meaning |
| ----- | ------- |
| `* * * * 0..15; d` | every minute (of every hour in every day in every year), from 0 second to 15 second |
| `* 10 1..5 8..10 .. 0; w` | from 8:00:00 in 10th Monday to 10:59:00 in 10th Friday in every year |
| `* 10 1 5 8.. .. ..; m` | first Friday in every October, from 8:00:00 to 23:59:59 |
| `* 10 * 8..10 .. ..; c` | every day in every October, from 8:00:00 to 10:59:59 |
This pattern has several rules as following:
1. At least one explicit `..` unit pattern should appear;
2. Only `..` or single number unit pattern should appear after a `..`;
3. If a single number pattern `s` occurs after `..`, it will be expanded to `s..s` automatically in this context;
4. You can omit integer on each side of `..`, default are `0` and `L1`, respectively; i.e., `..` equals `0..L1` or `1..L1`;
> L1 means the last one;
### Unit Range and L
L is a useful indicator to represent ordinal in reverse order. Since correct pattern range is essential for correct and fast computation, explicity is much desired; It is highly recommended to use L indicator when you need to represent numbers close to end of a unit range, especially for calendar units that the range could vary on different circumstances;
### Pattern with - /
When use `a-b/c`, you may encouter with a situation that `b` does not comply with the sequence which `a` and `c` define; in this context, the last number `a-b/c` represents is `max(a+c*i)` where i > 0 and i is integer;
i.e. 1-9/5 represents 1, 6
### Length, Omission, and Default
`Second` and `year` is not necessary, and to indicate `year`, `second` must be explicit first;
If `U` is the full number of units for each mode (see [table](#calendar-mode-and-indicator)), `U-1` means year is implicit, `U-2` means year and second are implicit.
`year` is always default to `*`;
`second` is default `0` in normal context, and `0..59` in span context;
### Examples
| expression | meaning |
| ----- | ------- |
| `* 1,L1 8 *; d` | every minute of 8 clock in first and last day of every year |
| `2000 1 1 * */3 0 0; m`| every 3 hour of every day in first week of Jan. 2000|
| `2000 L1 1,3,5 10 0 0; w` | every 10 O'Clock of Monday, Wednesday, Friday in last week of 2000 |
| `10 10 * *; c` | every minute (0 sec) in Oct. 10th, every year |
| `10 10 * * *; c` | every seconds in Oct. 10th, every year |
| `* * * * 0..15; d` | every minute (of every hour in every day in every year), from 0 second to 15 second |
Raw data
{
"_id": null,
"home_page": "https://github.com/RobbieL-nlp/ChronoX-python",
"name": "chronox-python",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "cron, chronos, period, time, date, datetime, chronox",
"author": "RobbieL-nlp",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/8a/55/d7a090e28293f8262b583ec734074438aaf597cf0444d80abbb6db7aa964/chronox-python-1.0.0.tar.gz",
"platform": null,
"description": "# ChronoX\n\n> The project details and documentation can be found [here](https://chronox-doc.vercel.app/); It also provides a online API (coming soon) with rust implementation; \n\n**ChronoX** is a project to extend the functionalities of conventional [cron](https://en.wikipedia.org/wiki/Cron) utility; \n\nIt provides more expressive power (day of year, month of week, span of time) by using expression (let's call it **cronx**) similar to the conventional one; \n\nBesides conventional next/prev 1 search, **ChronoX** provides convinient function to directly and efficiently compute the next/prev `n` occurence of desired pattern, \nwhere `n` could be extremely large! Most conventional implementation requires looping which leads to a *O*(n) time complexity, whereas **ChronoX** utilizes optimized algorithm to reduce the time complexity down to somewhere between **constant** and **log** between **ChronoX** rust implementation and a popular rust crate;\n\nIf you needs to express the following besides the conventional cron: \n- day of year \n- week of month\n- time span between start and end\n\nor, you needs to compute time **`N`** leaps away,\n\n**ChronoX** would be your right choice!\n\nThis is a python implementation of **ChronoX**. It requires using **cronx**, a cron like expression, see [cronx guide below](#cronx) or detail docs. \n\n### Install\n\n```bash\npip install chronox-python\n```\n> python >= 3.8\n\n### Usage\n\nThis package provides two main classes: `ChronoX` for time point and `ChronoXSpan` for time span.\n\nThe input and output should be encapsulated by `datetime` class from `datetime` module;\n\n```python\nfrom datetime import datetime\n```\n\n#### Time Point\n\n`ChronoX` class provides 3 main functions: `prev` and `next` to calculate previous and next time point respectively and `contains` to check if the passed in datetime can be represented by the pattern.\n\n```python\n\nfrom chronox import ChronoX\nfrom datetime import datetime\n\ncron = ChronoX(\"* * * 1,3,5 * * ; c\")\n\nassert cron.prev(datetime(2003, 11, 10, 6, 0, 6)) == datetime(2003, 11, 10, 6, 0, 5)\nassert cron.prev(datetime(2003, 11, 10, 6, 0, 6), 1) == datetime(2003, 11, 10, 6, 0, 5)\nassert cron.prev(datetime(2003, 11, 10, 6, 0, 6), leap=1) == datetime(2003, 11, 10, 6, 0, 5)\nassert cron.prev(datetime(2003, 11, 10, 6, 0, 6), leap=10) == datetime(2003, 11, 9, 5, 59, 50)\n\nassert cron.next(datetime(2003, 11, 10, 5, 59, 59)) == datetime(2003, 11, 11, 1, 0, 0)\n\n# If current datetime represented by the cron\ncron.contains(datetime.now())\n\n# is equivalent to\n\ndatetime.now() in cron\n\n```\n\nparameter for datetime is optional and default to datetime.now()\n\n#### Time Span\n\n`ChronoXSpan` provides a main function `contains`. It also provide `start` and `end` properties which reference decoded ChronoX instance for start and end pattern, you can utilize these two properties for calculation releted start or end pattern seperately. \n\n```python\nfrom chronox import ChronoXSpan\nfrom datetime import datetime\n\nperiod = ChronoXSpan(\"* 1,3,5 * 3..5 0 0 0; m\")\n\nassert period.contains(datetime(2003, 5, 16, 0, 0, 0))\n\n# is equivalent to\n\ndatetime(2003, 5, 16, 0, 0, 0).now() in cron\n\n# calculate next start time\nperiod.start.next()\n\n# calculate next end time\nperiod.end.next()\n\n\n```\n\n# cronx\n\nThis guide explains **cronx** expression by comparing it with conventional cron; \nif you are unfamiliar with cron, please read about [cron](https://en.wikipedia.org/wiki/Cron) first, or go to [detail](https://chronox-doc.vercel.app/cronx/detail) explaination directly.\n\n### More Expressive\n\nBeyond all the time pattern a conventional cron support, **cronx** also support the following pattern:\n1. `day of year`\n2. `week of month`\n3. `span of time` from `start time pattern` to `end time pattern` \n\nAll week date definition follows ISO standard, see [details](https://en.wikipedia.org/wiki/ISO_week_date)\n\n\nIn order to support these extra time patterns, **cronx** introduces the following main differences from the conventional cron:\n1. explicit indicator calendar mode\n2. different order of unit expression\n3. new character set `..` for span of time\n\nLet's go through them one by one.\n\n### Calendar Mode and Indicator \n\n>full # of units include three clock units: `hour`, `minute`, `second`\n\n| Token | Description | Calendar Combination | full # of units |\n| -------| ----------- | -------------------- | --------------- |\n| `d` | day of year | `year`, `day of year` | 5 |\n| `w` | week of year | `year`, `week of year`, `day of week` | 6 |\n| `m` | special month special month composed by week | `year`, `month`, `week of month`, `day of week` | 7 |\n| `c` | common mode | `year`, `month`, `day of month` | 6 |\n\nAll indicator tokens should be append to the end of expression string, and using `;` to seperate from main expression.\n\n\n### Order of Unit\nGenerally, **cronx** takes a reverse order compared to cron, that is from bigger unit to smaller one\n\n| mode | Order |\n| -------| ----------- |\n| `d` | `year` `day of year` `hour` `minute` `second` |\n| `w` | `year` `week of year` `day of week` `hour` `minute` `second` |\n| `m` | `year` `month` `week of month` `day of week` `hour` `minute` `second` |\n| `c` | `year` `month` `day of month` `hour` `minute` `second` |\n\n\n### Span of Time\n\nThis is a new concept, it represents a span or a block of time from a start to an end expressed by **cronx**, start and end occur in pairs, and connected by new character set `..` in **cronx**. \n\n| cronx | meaning |\n| ----- | ------- |\n| `* * * * 0..15; d` | every minute (of every hour in every day in every year), from 0 second to 15 second |\n| `* 10 1..5 8..10 .. 0; w` | from 8:00:00 in 10th Monday to 10:59:00 in 10th Friday in every year |\n| `* 10 1 5 8.. .. ..; m` | first Friday in every October, from 8:00:00 to 23:59:59 |\n| `* 10 * 8..10 .. ..; c` | every day in every October, from 8:00:00 to 10:59:59 |\n\nThis pattern has several rules as following:\n1. At least one explicit `..` unit pattern should appear;\n2. Only `..` or single number unit pattern should appear after a `..`;\n3. If a single number pattern `s` occurs after `..`, it will be expanded to `s..s` automatically in this context;\n4. You can omit integer on each side of `..`, default are `0` and `L1`, respectively; i.e., `..` equals `0..L1` or `1..L1`;\n> L1 means the last one; \n\n\n\n### Unit Range and L \n\nL is a useful indicator to represent ordinal in reverse order. Since correct pattern range is essential for correct and fast computation, explicity is much desired; It is highly recommended to use L indicator when you need to represent numbers close to end of a unit range, especially for calendar units that the range could vary on different circumstances;\n\n### Pattern with - /\n\nWhen use `a-b/c`, you may encouter with a situation that `b` does not comply with the sequence which `a` and `c` define; in this context, the last number `a-b/c` represents is `max(a+c*i)` where i > 0 and i is integer; \n\ni.e. 1-9/5 represents 1, 6\n\n### Length, Omission, and Default\n\n`Second` and `year` is not necessary, and to indicate `year`, `second` must be explicit first; \n\nIf `U` is the full number of units for each mode (see [table](#calendar-mode-and-indicator)), `U-1` means year is implicit, `U-2` means year and second are implicit.\n\n`year` is always default to `*`;\n\n`second` is default `0` in normal context, and `0..59` in span context;\n\n### Examples\n| expression | meaning |\n| ----- | ------- |\n| `* 1,L1 8 *; d` | every minute of 8 clock in first and last day of every year |\n| `2000 1 1 * */3 0 0; m`| every 3 hour of every day in first week of Jan. 2000|\n| `2000 L1 1,3,5 10 0 0; w` | every 10 O'Clock of Monday, Wednesday, Friday in last week of 2000 |\n| `10 10 * *; c` | every minute (0 sec) in Oct. 10th, every year |\n| `10 10 * * *; c` | every seconds in Oct. 10th, every year |\n| `* * * * 0..15; d` | every minute (of every hour in every day in every year), from 0 second to 15 second |\n\n\n\n\n\n\n\n",
"bugtrack_url": null,
"license": null,
"summary": "An innovated and extended periodic cron time utility, it provides more expressive power by using expression similar to cron and optimized algorithm implementation for large number of steps search.",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/RobbieL-nlp/ChronoX-python"
},
"split_keywords": [
"cron",
" chronos",
" period",
" time",
" date",
" datetime",
" chronox"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fc28a1197247092c35cf59e6b114580fa1e5ea2289b9565d70d829bdb84252db",
"md5": "834e75f22e0941063282393e22e1931e",
"sha256": "e744591e254ce472a559edf2cb3b461785f9deef0fac9ad9dc690f95dc5c6739"
},
"downloads": -1,
"filename": "chronox_python-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "834e75f22e0941063282393e22e1931e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 21852,
"upload_time": "2024-03-20T19:32:15",
"upload_time_iso_8601": "2024-03-20T19:32:15.895256Z",
"url": "https://files.pythonhosted.org/packages/fc/28/a1197247092c35cf59e6b114580fa1e5ea2289b9565d70d829bdb84252db/chronox_python-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8a55d7a090e28293f8262b583ec734074438aaf597cf0444d80abbb6db7aa964",
"md5": "a7a839d124601a6d7aede6bc21eb2a63",
"sha256": "55a888660d743c2b85ed9cfa8bb97d23164092e105fbff8532ebaf6bc396536f"
},
"downloads": -1,
"filename": "chronox-python-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "a7a839d124601a6d7aede6bc21eb2a63",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 17479,
"upload_time": "2024-03-20T19:32:17",
"upload_time_iso_8601": "2024-03-20T19:32:17.741366Z",
"url": "https://files.pythonhosted.org/packages/8a/55/d7a090e28293f8262b583ec734074438aaf597cf0444d80abbb6db7aa964/chronox-python-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-20 19:32:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "RobbieL-nlp",
"github_project": "ChronoX-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "chronox-python"
}