1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#![warn(missing_docs)] #![warn(missing_doc_code_examples)] //! A library for creating and consuming Cron expressions. It supports some extended syntax. //! //! # Overview //! Each expression consists of five fields, space separated, representing different parts of the day in the following order: //! * Minute //! * Hour //! * Day of Month //! * Month //! * Day of Week //! //! Each field consists of some number of values, comma separated, indicating when the expression is a match. //! In addition to the regular: //! * [Single value](#single-values) //! * [Inclusive range of values](#range-values) //! * [Wildcard](#wildcard-values) //! //! Expressions can also include: //! * [Step ranges](#step-range-values) //! * [Weekday nearest to Day of Month](#weekday-nearest-to-day-of-month) //! * [Last Day of Month (with or without an offset)](#last-day-of-month) //! * [Nth Day of Week](#nth-day-of-week) //! * [Last Day of Week](#last-day-of-week) //! //! Additionally, Month and Day of Week values can be represented numerically or with a three-letter abbreviation (JAN -> 01 or wed -> 3, respectively). //! # Examples //! ## Wildcard Values //! An expression that is always a match. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let anytime = "* * * * *".parse::<CronExpression>()?; //! assert_eq!(true, anytime.is_match(&Utc::now())); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Single Values //! An expression that matches at the start of a new year. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let new_year = "0 0 1 1 *".parse::<CronExpression>()?; //! assert_eq!(true, new_year.is_match(&"2021-01-01T00:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(false, new_year.is_match(&"2021-01-01T00:01:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Range Values //! An expression that matches in the middle of everything. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let middles = "15-45 6-18 10-20 3-9 2-4".parse::<CronExpression>()?; //! assert_eq!(true, middles.is_match(&"2021-04-13T07:24:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(false, middles.is_match(&"2021-04-13T18:46:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Step Range Values //! An expression that matches on even minutes in even hours on odd days in odd months. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let steps = "*/2 */2 */2 */2 *".parse::<CronExpression>()?; //! assert_eq!(true, steps.is_match(&"2021-01-05T06:44:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(false, steps.is_match(&"2021-01-05T06:43:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Weekday Nearest to Day of Month //! An expression that matches the weekday nearest to the 10th in August. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let tenth = "* * 10W Aug *".parse::<CronExpression>()?; //! assert_eq!(false, tenth.is_match(&"2019-08-10T00:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(true, tenth.is_match(&"2019-08-09T00:00:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Last Day of Month //! An expression that matches on the two last days of every month. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let last_two = "* * L,L-1 * *".parse::<CronExpression>()?; //! assert_eq!(false, last_two.is_match(&"2021-04-28T00:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(true, last_two.is_match(&"2021-04-29T00:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(true, last_two.is_match(&"2021-04-30T00:00:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Nth Day of Week //! An expression that matches on the 2nd Monday of June. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let monday = "* * * jun 1#2".parse::<CronExpression>()?; //! assert_eq!(false, monday.is_match(&"2021-06-07T12:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(true, monday.is_match(&"2021-06-14T12:00:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` //! ## Last Day of Week //! An expression that matches on the last Friday of every month. //! ``` //! use chrono::{DateTime, Utc}; //! use curds_cron::CronExpression; //! let friday = "* * * * FriL".parse::<CronExpression>()?; //! assert_eq!(false, friday.is_match(&"2021-01-22T00:00:00Z".parse::<DateTime<Utc>>()?)); //! assert_eq!(true, friday.is_match(&"2021-01-29T00:00:00Z".parse::<DateTime<Utc>>()?)); //! # Ok::<(), Box<dyn std::error::Error>>(()) //! ``` mod datepart; mod expression; mod field; mod parsing; mod value; use field::CronField; use parsing::parser::{CronFieldParser, CronValueParsingHandler, CurdsCronParser}; use value::CronValue; use chrono::{DateTime, Datelike, Duration, TimeZone, Timelike, Weekday}; use lazy_static::lazy_static; use regex::Regex; use std::fmt::{Debug, Display, Error, Formatter}; use std::str::FromStr; #[cfg(test)] use mockall::*; #[cfg(test)] use mockall::predicate::*; #[cfg(test)] use chrono::Utc; #[cfg(test)] use parsing::parser::{MockCronFieldParser, MockCronValueParsingHandler}; pub use expression::CronExpression; pub use datepart::CronDatePart; pub use parsing::error::CronParsingError;