cron-parser
Advanced tools
Comparing version 4.9.0 to 5.0.0
130
package.json
{ | ||
"name": "cron-parser", | ||
"version": "4.9.0", | ||
"version": "5.0.0", | ||
"description": "Node.js library for parsing crontab instructions", | ||
"main": "lib/parser.js", | ||
"types": "types/index.d.ts", | ||
"typesVersions": { | ||
"<4.1": { | ||
"*": [ | ||
"types/ts3/*" | ||
] | ||
} | ||
}, | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"main": "dist/index.js", | ||
"types": "dist/types/index.d.ts", | ||
"type": "commonjs", | ||
"scripts": { | ||
"test:tsd": "tsd", | ||
"test:unit": "TZ=UTC tap ./test/*.js", | ||
"test:cover": "TZ=UTC tap --coverage-report=html ./test/*.js", | ||
"clean": "rimraf dist", | ||
"bench": "cross-env node -r ts-node/register benchmarks/index.ts", | ||
"bench:pattern": "cross-env node -r ts-node/register benchmarks/pattern.ts", | ||
"bench:clean": "rimraf benchmarks/versions && rimraf benchmarks/results", | ||
"build": "npm run clean && tsc -p tsconfig.json", | ||
"prepublishOnly": "npm run build", | ||
"prepare": "husky && npm run build", | ||
"precommit": "lint-staged", | ||
"lint": "eslint .", | ||
"lint:fix": "eslint --fix .", | ||
"test": "npm run lint && npm run test:unit && npm run test:tsd" | ||
"lint:debug": "cross-env DEBUG=eslint:cli-engine eslint .", | ||
"format": "prettier --write \"**/*.{ts,js,json,md}\"", | ||
"format:check": "prettier --check \"**/*.{ts,js,json,md}\"", | ||
"test:unit": "cross-env TZ=UTC jest", | ||
"test:coverage": "cross-env TZ=UTC jest --coverage", | ||
"generate-badges": "jest-coverage-badges", | ||
"test:types": "npm run build && tsd", | ||
"test": "cross-env TZ=UTC npm run lint && npm run test:types && npm run test:coverage && npm run generate-badges", | ||
"docs": "rimraf docs && typedoc --out docs --readme none --name 'CronParser' src" | ||
}, | ||
"files": [ | ||
"dist", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"dependencies": { | ||
"luxon": "^3.5.0" | ||
}, | ||
"devDependencies": { | ||
"@tsd/typescript": "^5.7.3", | ||
"@types/jest": "^29.5.14", | ||
"@types/luxon": "^3.4.2", | ||
"@types/node": "^22.13.0", | ||
"@typescript-eslint/eslint-plugin": "^8.22.0", | ||
"@typescript-eslint/parser": "^8.22.0", | ||
"chalk": "^4.1.2", | ||
"cli-table3": "^0.6.5", | ||
"cross-env": "^7.0.3", | ||
"eslint": "^9.19.0", | ||
"eslint-config-prettier": "^10.0.1", | ||
"eslint-plugin-prettier": "^5.2.3", | ||
"husky": "^9.1.7", | ||
"jest": "^29.7.0", | ||
"jest-coverage-badges": "^1.0.0", | ||
"jest-runner-tsd": "^6.0.0", | ||
"lint-staged": "^15.4.3", | ||
"prettier": "^3.4.2", | ||
"rimraf": "^6.0.1", | ||
"sinon": "^19.0.2", | ||
"ts-jest": "^29.2.5", | ||
"ts-node": "^10.9.2", | ||
"tsd": "^0.31.2", | ||
"typedoc": "^0.27.6", | ||
"typescript": "^5.7.3" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.{ts,js,json}": [ | ||
"prettier --write" | ||
] | ||
}, | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"browser": { | ||
"fs": false | ||
}, | ||
"tsd": { | ||
"directory": "tests" | ||
}, | ||
"repository": { | ||
@@ -55,38 +113,6 @@ "type": "git", | ||
"Andy Thompson <me@andytson.com>", | ||
"Regev Brody <regevbr@gmail.com>" | ||
"Regev Brody <regevbr@gmail.com>", | ||
"Michael Hobbs <michael.lee.hobbs@gmail.com>" | ||
], | ||
"license": "MIT", | ||
"dependencies": { | ||
"luxon": "^3.2.1" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^8.27.0", | ||
"sinon": "^15.0.1", | ||
"tap": "^16.3.3", | ||
"tsd": "^0.26.0" | ||
}, | ||
"engines": { | ||
"node": ">=12.0.0" | ||
}, | ||
"browser": { | ||
"fs": false | ||
}, | ||
"tap": { | ||
"check-coverage": false | ||
}, | ||
"tsd": { | ||
"directory": "test", | ||
"compilerOptions": { | ||
"lib": [ | ||
"es2017", | ||
"dom" | ||
] | ||
} | ||
}, | ||
"files": [ | ||
"lib", | ||
"types", | ||
"LICENSE", | ||
"README.md" | ||
] | ||
"license": "MIT" | ||
} |
324
README.md
@@ -1,15 +0,18 @@ | ||
cron-parser | ||
================ | ||
# cron-parser | ||
[![Build Status](https://github.com/harrisiirak/cron-parser/actions/workflows/push.yml/badge.svg?branch=master)](https://github.com/harrisiirak/cron-parser/actions/workflows/push.yml) | ||
[![NPM version](https://badge.fury.io/js/cron-parser.png)](http://badge.fury.io/js/cron-parser) | ||
![Statements](./coverage/badge-statements.svg) | ||
Node.js library for parsing and manipulating crontab instructions. It includes support for timezones and DST transitions. | ||
A JavaScript library for parsing and manipulating cron expressions. Features timezone support, DST handling, and iterator capabilities. | ||
__Compatibility__ | ||
Node >= 12.0.0 | ||
TypeScript >= 4.2 | ||
[API documentation](https://harrisiirak.github.io/cron-parser/) | ||
Setup | ||
======== | ||
## Requirements | ||
- Node.js >= 18 | ||
- TypeScript >= 5 | ||
## Installation | ||
```bash | ||
@@ -19,4 +22,3 @@ npm install cron-parser | ||
Supported format | ||
======== | ||
## Cron Format | ||
@@ -26,152 +28,256 @@ ``` | ||
┬ ┬ ┬ ┬ ┬ ┬ | ||
│ │ │ │ │ | | ||
│ │ │ │ │ └ day of week (0 - 7, 1L - 7L) (0 or 7 is Sun) | ||
│ │ │ │ └───── month (1 - 12) | ||
│ │ │ └────────── day of month (1 - 31, L) | ||
│ │ └─────────────── hour (0 - 23) | ||
│ └──────────────────── minute (0 - 59) | ||
└───────────────────────── second (0 - 59, optional) | ||
│ │ │ │ │ │ | ||
│ │ │ │ │ └─ day of week (0-7, 1L-7L) (0 or 7 is Sun) | ||
│ │ │ │ └────── month (1-12, JAN-DEC) | ||
│ │ │ └─────────── day of month (1-31, L) | ||
│ │ └──────────────── hour (0-23) | ||
│ └───────────────────── minute (0-59) | ||
└────────────────────────── second (0-59, optional) | ||
``` | ||
Supports mixed use of ranges and range increments (W character not supported currently). See tests for examples. | ||
### Special Characters | ||
Usage | ||
======== | ||
| Character | Description | Example | | ||
| --------- | ------------------------- | --------------------------------------------- | | ||
| `*` | Any value | `* * * * *` (every minute) | | ||
| `?` | Any value (alias for `*`) | `? * * * *` (every minute) | | ||
| `,` | Value list separator | `1,2,3 * * * *` (1st, 2nd, and 3rd minute) | | ||
| `-` | Range of values | `1-5 * * * *` (every minute from 1 through 5) | | ||
| `/` | Step values | `*/5 * * * *` (every 5th minute) | | ||
| `L` | Last day of month/week | `0 0 L * *` (midnight on last day of month) | | ||
| `#` | Nth day of month | `0 0 * * 1#1` (first Monday of month) | | ||
Simple expression. | ||
### Predefined Expressions | ||
```javascript | ||
var parser = require('cron-parser'); | ||
| Expression | Description | Equivalent | | ||
| ----------- | ----------------------------------------- | --------------- | | ||
| `@yearly` | Once a year at midnight of January 1 | `0 0 0 1 1 *` | | ||
| `@monthly` | Once a month at midnight of first day | `0 0 0 1 * *` | | ||
| `@weekly` | Once a week at midnight on Sunday | `0 0 0 * * 0` | | ||
| `@daily` | Once a day at midnight | `0 0 0 * * *` | | ||
| `@hourly` | Once an hour at the beginning of the hour | `0 0 * * * *` | | ||
| `@minutely` | Once a minute | `0 * * * * *` | | ||
| `@secondly` | Once a second | `* * * * * *` | | ||
| `@weekdays` | Every weekday at midnight | `0 0 0 * * 1-5` | | ||
| `@weekends` | Every weekend at midnight | `0 0 0 * * 0,6` | | ||
### Field Values | ||
| Field | Values | Special Characters | Aliases | | ||
| ------------ | ------ | --------------------------- | ------------------------------ | | ||
| second | 0-59 | `*` `?` `,` `-` `/` | | | ||
| minute | 0-59 | `*` `?` `,` `-` `/` | | | ||
| hour | 0-23 | `*` `?` `,` `-` `/` | | | ||
| day of month | 1-31 | `*` `?` `,` `-` `/` `L` | | | ||
| month | 1-12 | `*` `?` `,` `-` `/` | `JAN`-`DEC` | | ||
| day of week | 0-7 | `*` `?` `,` `-` `/` `L` `#` | `SUN`-`SAT` (0 or 7 is Sunday) | | ||
## Options | ||
| Option | Type | Description | | ||
| ----------- | ------------------------ | -------------------------------------------------------------- | | ||
| currentDate | Date \| string \| number | Current date. Defaults to current local time in UTC | | ||
| endDate | Date \| string \| number | End date of iteration range. Sets iteration range end point | | ||
| startDate | Date \| string \| number | Start date of iteration range. Set iteration range start point | | ||
| tz | string | Timezone (e.g., 'Europe/London') | | ||
| strict | boolean | Enable strict mode validation | | ||
When using string dates, the following formats are supported: | ||
- ISO8601 | ||
- HTTP and RFC2822 | ||
- SQL | ||
## Basic Usage | ||
### Expression Parsing | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
try { | ||
var interval = parser.parseExpression('*/2 * * * *'); | ||
const interval = CronExpressionParser.parse('*/2 * * * *'); | ||
console.log('Date: ', interval.next().toString()); // Sat Dec 29 2012 00:42:00 GMT+0200 (EET) | ||
console.log('Date: ', interval.next().toString()); // Sat Dec 29 2012 00:44:00 GMT+0200 (EET) | ||
// Get next date | ||
console.log('Next:', interval.next().toString()); | ||
// Get next 3 dates | ||
console.log( | ||
'Next 3:', | ||
interval.take(3).map((date) => date.toString()), | ||
); | ||
console.log('Date: ', interval.prev().toString()); // Sat Dec 29 2012 00:42:00 GMT+0200 (EET) | ||
console.log('Date: ', interval.prev().toString()); // Sat Dec 29 2012 00:40:00 GMT+0200 (EET) | ||
// Get previous date | ||
console.log('Previous:', interval.prev().toString()); | ||
} catch (err) { | ||
console.log('Error: ' + err.message); | ||
console.log('Error:', err.message); | ||
} | ||
``` | ||
Iteration with limited timespan. Also returns ES6 compatible iterator (when iterator flag is set to true). | ||
### With Options | ||
```javascript | ||
var parser = require('cron-parser'); | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
var options = { | ||
currentDate: new Date('Wed, 26 Dec 2012 12:38:53 UTC'), | ||
endDate: new Date('Wed, 26 Dec 2012 14:40:00 UTC'), | ||
iterator: true | ||
const options = { | ||
currentDate: '2023-01-01T00:00:00Z', | ||
endDate: '2024-01-01T00:00:00Z', | ||
tz: 'Europe/London', | ||
}; | ||
try { | ||
var interval = parser.parseExpression('*/22 * * * *', options); | ||
const interval = CronExpressionParser.parse('0 0 * * *', options); | ||
console.log('Next:', interval.next().toString()); | ||
} catch (err) { | ||
console.log('Error:', err.message); | ||
} | ||
``` | ||
while (true) { | ||
try { | ||
var obj = interval.next(); | ||
console.log('value:', obj.value.toString(), 'done:', obj.done); | ||
} catch (e) { | ||
break; | ||
} | ||
} | ||
### Crontab File Operations | ||
// value: Wed Dec 26 2012 14:44:00 GMT+0200 (EET) done: false | ||
// value: Wed Dec 26 2012 15:00:00 GMT+0200 (EET) done: false | ||
// value: Wed Dec 26 2012 15:22:00 GMT+0200 (EET) done: false | ||
// value: Wed Dec 26 2012 15:44:00 GMT+0200 (EET) done: false | ||
// value: Wed Dec 26 2012 16:00:00 GMT+0200 (EET) done: false | ||
// value: Wed Dec 26 2012 16:22:00 GMT+0200 (EET) done: true | ||
For working with crontab files, use the CronFileParser: | ||
```typescript | ||
import { CronFileParser } from 'cron-parser'; | ||
// Async file parsing | ||
try { | ||
const result = await CronFileParser.parseFile('/path/to/crontab'); | ||
console.log('Variables:', result.variables); | ||
console.log('Expressions:', result.expressions); | ||
console.log('Errors:', result.errors); | ||
} catch (err) { | ||
console.log('Error: ' + err.message); | ||
console.log('Error:', err.message); | ||
} | ||
// Sync file parsing | ||
try { | ||
const result = CronFileParser.parseFileSync('/path/to/crontab'); | ||
console.log('Variables:', result.variables); | ||
console.log('Expressions:', result.expressions); | ||
console.log('Errors:', result.errors); | ||
} catch (err) { | ||
console.log('Error:', err.message); | ||
} | ||
``` | ||
Timezone support | ||
## Advanced Features | ||
```javascript | ||
var parser = require('cron-parser'); | ||
### Strict Mode | ||
var options = { | ||
currentDate: '2016-03-27 00:00:01', | ||
tz: 'Europe/Athens' | ||
In several implementations of CRON, it's ambiguous to specify both the Day Of Month and Day Of Week parameters simultaneously, as it's unclear which one should take precedence. Despite this ambiguity, this library allows both parameters to be set by default, although the resultant behavior might not align with your expectations. | ||
To resolve this ambiguity, you can activate the strict mode of the library. In strict mode, the library prevents the simultaneous setting of both Day Of Month and Day Of Week, effectively serving as a validation method for user inputs. | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
// Specifies a schedule that occurs at 12:00 on every day-of-month from 1 through 31 and on Monday | ||
const options = { | ||
currentDate: new Date('Mon, 12 Sep 2022 14:00:00'), | ||
strict: true, | ||
}; | ||
try { | ||
var interval = parser.parseExpression('0 * * * *', options); | ||
console.log('Date: ', interval.next().toString()); // Date: Sun Mar 27 2016 01:00:00 GMT+0200 | ||
console.log('Date: ', interval.next().toString()); // Date: Sun Mar 27 2016 02:00:00 GMT+0200 | ||
console.log('Date: ', interval.next().toString()); // Date: Sun Mar 27 2016 04:00:00 GMT+0300 (Notice DST transition) | ||
// This will throw an error in strict mode | ||
CronExpressionParser.parse('0 0 12 1-31 * 1', options); | ||
} catch (err) { | ||
console.log('Error: ' + err.message); | ||
console.log('Error:', err.message); | ||
// Error: Cannot use both dayOfMonth and dayOfWeek together in strict mode! | ||
} | ||
``` | ||
Manipulation | ||
### Last Day of Month/Week Support | ||
```javascript | ||
var parser = require('cron-parser'); | ||
The library supports parsing the range `0L - 7L` in the `weekday` position of the cron expression, where the `L` means "last occurrence of this weekday for the month in progress". | ||
var interval = parser.parseExpression('0 7 * * 0-4'); | ||
var fields = JSON.parse(JSON.stringify(interval.fields)); // Fields is immutable | ||
fields.hour = [8]; | ||
fields.minute = [29]; | ||
fields.dayOfWeek = [1,3,4,5,6,7]; | ||
var modifiedInterval = parser.fieldsToExpression(fields); | ||
var cronString = modifiedInterval.stringify(); | ||
console.log(cronString); // "29 8 * * 1,3-7" | ||
For example, the following expression will run on the last Monday of the month at midnight: | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
// Last Monday of every month at midnight | ||
const lastMonday = CronExpressionParser.parse('0 0 0 * * 1L'); | ||
// You can also combine L expressions with other weekday expressions | ||
// This will run every Monday and the last Wednesday of the month | ||
const mixedWeekdays = CronExpressionParser.parse('0 0 0 * * 1,3L'); | ||
// Last day of every month | ||
const lastDay = CronExpressionParser.parse('0 0 L * *'); | ||
``` | ||
Options | ||
======== | ||
### Using Iterator | ||
* *currentDate* - Start date of the iteration | ||
* *endDate* - End date of the iteration | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
`currentDate` and `endDate` accept `string`, `integer` and `Date` as input. | ||
const interval = CronExpressionParser.parse('0 */2 * * *'); | ||
In case of using `string` as input, not every string format accepted | ||
by the `Date` constructor will work correctly. | ||
The supported formats are: | ||
- [`ISO8601`](https://moment.github.io/luxon/#/parsing?id=iso-8601) | ||
- [`HTTP and RFC2822`](https://moment.github.io/luxon/#/parsing?id=http-and-rfc2822) | ||
- [`SQL`](https://moment.github.io/luxon/#/parsing?id=sql) | ||
// Using for...of | ||
for (const date of interval) { | ||
console.log('Iterator value:', date.toString()); | ||
if (someCondition) break; | ||
} | ||
The reason being that those are the formats accepted by the | ||
[`luxon`](https://moment.github.io/luxon/) library which is being used to handle dates. | ||
// Using take() for a specific number of iterations | ||
const nextFiveDates = interval.take(5); | ||
console.log( | ||
'Next 5 dates:', | ||
nextFiveDates.map((date) => date.toString()), | ||
); | ||
``` | ||
Using `Date` as an input can be problematic specially when using the `tz` option. The issue being that, when creating a new `Date` object without | ||
any timezone information, it will be created in the timezone of the system that is running the code. This (most of times) won't be what the user | ||
will be expecting. Using one of the supported `string` formats will solve the issue(see timezone example). | ||
### Timezone Support | ||
* *iterator* - Return ES6 compatible iterator object | ||
* *utc* - Enable UTC | ||
* *tz* - Timezone string. It won't be used in case `utc` is enabled | ||
The library provides robust timezone support using Luxon, handling DST transitions correctly: | ||
Last weekday of the month | ||
========================= | ||
```typescript | ||
import { CronExpressionParser } from 'cron-parser'; | ||
This library supports parsing the range `0L - 7L` in the `weekday` position of | ||
the cron expression, where the `L` means "last occurrence of this weekday for | ||
the month in progress". | ||
const options = { | ||
currentDate: '2023-03-26T01:00:00', | ||
tz: 'Europe/London', | ||
}; | ||
For example, the following expression will run on the last monday of the month | ||
at midnight: | ||
const interval = CronExpressionParser.parse('0 * * * *', options); | ||
// Will correctly handle DST transition | ||
console.log('Next dates during DST transition:'); | ||
console.log(interval.next().toString()); | ||
console.log(interval.next().toString()); | ||
console.log(interval.next().toString()); | ||
``` | ||
0 0 0 * * 1L | ||
### Field Manipulation | ||
You can modify cron fields programmatically using `CronFieldCollection.from` and construct a new expression: | ||
```typescript | ||
import { CronExpressionParser, CronFieldCollection, CronHour, CronMinute } from 'cron-parser'; | ||
// Parse original expression | ||
const interval = CronExpressionParser.parse('0 7 * * 1-5'); | ||
// Create new collection with modified fields using raw values | ||
const modified = CronFieldCollection.from(interval.fields, { | ||
hour: [8], | ||
minute: [30], | ||
dayOfWeek: [1, 3, 5], | ||
}); | ||
console.log(modified.stringify()); // "30 8 * * 1,3,5" | ||
// You can also use CronField instances | ||
const modified2 = CronFieldCollection.from(interval.fields, { | ||
hour: new CronHour([15]), | ||
minute: new CronMinute([30]), | ||
}); | ||
console.log(modified2.stringify()); // "30 15 * * 1-5" | ||
``` | ||
The library also supports combining `L` expressions with other weekday | ||
expressions. For example, the following cron will run every Monday as well | ||
as the last Wednesday of the month: | ||
The `CronFieldCollection.from` method accepts either CronField instances or raw values that would be valid for creating new CronField instances. This is particularly useful when you need to modify only specific fields while keeping others unchanged. | ||
``` | ||
0 0 0 * * 1,3L | ||
``` | ||
## License | ||
MIT |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
120785
33
2924
282
25
2
Updatedluxon@^3.5.0