Rust flavor of the popular cron scheduler croner.

Overview

Croner

Croner is a fully featured, lightweight, efficient Rust library for parsing and evaluating cron patterns. Designed with simplicity and performance in mind, it provides Rust developers with a tool to schedule tasks efficiently, following the familiar cron syntax.

This is the Rust flavor of the popular JavaScript/TypeScript cron parser croner.

Features

  • Parse and evaluate cron expressions to calculate upcoming execution times.
  • Schedule tasks in separate threads based on cron patterns, enabling concurrent task execution.
  • Supports extended Vixie-cron patterns with additional specifiers such as L for the last day and weekday of the month, # for the nth weekday of the month and W for closest weekday to a day of month.
  • Evaulate cron expressions across different time zones.
  • Compatible with chrono and (optionally) chrono-tz.
  • Robust error handling.
  • Control execution flow with the ability to pause, resume, or stop scheduled tasks.
  • Operates in-memory without the need for persistent storage or configuration files.
  • Highly optimized method of finding future/past matches.
  • No dependencies except chrono.

Getting Started

Prerequisites

Ensure you have Rust installed on your machine. If not, you can get it from the official Rust website.

Installation

Add croner to your Cargo.toml dependencies:

Please note that croner for Rust is work in progress, and not production ready

[dependencies]
croner = "1.0.0" # Adjust the version as necessary

Usage

Here's a quick example to get you started with matching current time, and finding the next occurrence. is_time_matching takes a chrono DateTime:

use croner::Cron;
use chrono::Local;

fn main() {

    // Parse cron expression
    let cron_all: Cron = "0 18 * * * 5".parse().expect("Couldn't parse cron string");

    // Compare cron pattern with current local time
    let time = Local::now();
    let matches_all = cron_all.is_time_matching(&time).unwrap();

    // Get next match
    let next = cron_all.find_next_occurrence(&time, false).unwrap();

    // Output results
    println!("Time is: {}", time);
    println!("Pattern \"{}\" does {} time {}", cron_all.pattern.to_string(), if matches_all { "match" } else { "not match" }, time );
    println!("Pattern \"{}\" will match next time at {}", cron_all.pattern.to_string(), next);

}

To match against a non local timezone, croner supports zoned chrono DateTime's DateTime<Tz>. To use a named time zone, you can utilize the chrono-tz crate.

use croner::Cron;
use chrono::Local;
use chrono_tz::Tz;

fn main() {
    // Parse cron expression
    let cron = Cron::parse("0 18 * * * 5").expect("Couldn't parse cron string");

    // Choose a different time zone, for example America/New_York
    let est_timezone: Tz = "America/New_York".parse().expect("Invalid timezone");

    // Find the next occurrence in EST
    let time_est = Local::now().with_timezone(&est_timezone);
    let next_est = cron.find_next_occurrence(&time_est, false).unwrap();

    // Output results for EST
    println!("EST time is: {}", time_est);
    println!(
        "Pattern \"{}\" will match next time at (EST): {}",
        cron.pattern.to_string(),
        next_est
    );
}

Here is a basic example to schedule a task:

use croner::Cron;
use croner::scheduler::CronScheduler;
use chrono::Utc;

use std::thread;

fn main() {
    let cron: Cron = "0/5 * * * * *".parse().expect("Invalid cron expression");
    let scheduler = CronScheduler::new(cron, Utc);

    scheduler.start(|| {
        println!("Task executed at {:?}", Utc::now());
    });

    // The task can be paused, resumed, or stopped as needed
    // scheduler.pause();
    // scheduler.resume();
    // scheduler.stop();
    
    // For demonstration purposes, let's run for some time then stop
    thread::sleep(std::time::Duration::from_secs(20));
}

Pattern

The expressions used by Croner are very similar to those of Vixie Cron, but with a few additions and changes as outlined below:

// ┌──────────────── (optional) second (0 - 59)
// │ ┌────────────── minute (0 - 59)
// │ │ ┌──────────── hour (0 - 23)
// │ │ │ ┌────────── day of month (1 - 31)
// │ │ │ │ ┌──────── month (1 - 12, JAN-DEC)
// │ │ │ │ │ ┌────── day of week (0 - 6, SUN-Mon)
// │ │ │ │ │ │       (0 to 6 are Sunday to Saturday; 7 is Sunday, the same as 0)
// │ │ │ │ │ │
// * * * * * *
  • Croner expressions have the following additional modifiers:
    • ?: In the Rust version of croner, a questionmark behaves just as *, to allow for legacy cron patterns to be used.
    • L: The letter 'L' can be used in the day of the month field to indicate the last day of the month. When used in the day of the week field in conjunction with the # character, it denotes the last specific weekday of the month. For example, 5#L represents the last Friday of the month.
    • #: The # character specifies the "nth" occurrence of a particular day within a month. For example, supplying 5#2 in the day of week field signifies the second Friday of the month. This can be combined with ranges and supports day names. For instance, MON-FRI#2 would match the Monday through Friday of the second week of the month.
    • W: The character 'W' is used to specify the closest weekday to a given day in the day of the month field. For example, 15W will match the closest weekday to the 15th of the month. If the specified day falls on a weekend (Saturday or Sunday), the pattern will match the closest weekday before or after that date. For instance, if the 15th is a Saturday, 15W will match the 14th (Friday), and if the 15th is a Sunday, it will match the 16th (Monday).
Field Required Allowed values Allowed special characters Remarks
Seconds Optional 0-59 * , - / ?
Minutes Yes 0-59 * , - / ?
Hours Yes 0-23 * , - / ?
Day of Month Yes 1-31 * , - / ? L W
Month Yes 1-12 or JAN-DEC * , - / ?
Day of Week Yes 0-7 or SUN-MON * , - / ? # L 0 to 6 are Sunday to Saturday
7 is Sunday, the same as 0
# is used to specify nth occurrence of a weekday

Note Weekday and month names are case-insensitive. Both MON and mon work. When using L in the Day of Week field, it affects all specified weekdays. For example, 5-6#L means the last Friday and Saturday in the month." The # character can be used to specify the "nth" weekday of the month. For example, 5#2 represents the second Friday of the month.

It is also possible to use the following "nicknames" as pattern.

Nickname Description
@yearly Run once a year, ie. "0 0 1 1 *".
@annually Run once a year, ie. "0 0 1 1 *".
@monthly Run once a month, ie. "0 0 1 * *".
@weekly Run once a week, ie. "0 0 * * 0".
@daily Run once a day, ie. "0 0 * * *".
@hourly Run once an hour, ie. "0 * * * *".

Documentation

For detailed usage and API documentation, visit Croner on docs.rs.

Development

To start developing in the Croner project:

  1. Clone the repository.
  2. Navigate into the project directory.
  3. Build the project using cargo build.
  4. Run tests with cargo test.
  5. Run demo with cargo run --example pattern_demo

Contributing

We welcome contributions! Please feel free to submit a pull request or open an issue.

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Disclaimer

Please note that Croner is currently in its early stages of development. As such, the API is subject to change in future releases, adhering to semantic versioning principles. We recommend keeping this in mind when integrating Croner into your projects.

Contact

If you have any questions or feedback, please open an issue in the repository and we'll get back to you as soon as possible.

You might also like...
auto-rust is an experimental project that aims to automatically generate Rust code with LLM (Large Language Models) during compilation, utilizing procedural macros.
auto-rust is an experimental project that aims to automatically generate Rust code with LLM (Large Language Models) during compilation, utilizing procedural macros.

Auto Rust auto-rust is an experimental project that aims to automatically generate Rust code with LLM (Large Language Models) during compilation, util

Rusty Shellcode Reflective DLL Injection (sRDI) - A small reflective loader in Rust 4KB in size for generating position-independent code (PIC) in Rust.
Rusty Shellcode Reflective DLL Injection (sRDI) - A small reflective loader in Rust 4KB in size for generating position-independent code (PIC) in Rust.

Shellcode Reflective DLL Injection (sRDI) Shellcode reflective DLL injection (sRDI) is a process injection technique that allows us to convert a given

This rust compiler backend emmits valid CLR IR, enambling you to use Rust in .NET projects

What is rustc_codegen_clr? NOTE: this project is a very early proof-of-concept This is a compiler backend for rustc which targets the .NET platform an

RustGPT is a ChatGPT UI built with Rust + HTMX: the power of Rust coupled with the simplicity of HTMX 💚

RustGPT 🦀✨ RustGPT.Blog.Post.mp4 Welcome to the RustGPT repository! Here, you'll find a web ChatGPT clone entirely crafted using Rust and HTMX, where

Rust API Server: A versatile template for building RESTful interfaces, designed for simplicity in setup and configuration using the Rust programming language.
Rust API Server: A versatile template for building RESTful interfaces, designed for simplicity in setup and configuration using the Rust programming language.

RUST API SERVER Introduction Welcome to the Rust API Server! This server provides a simple REST interface for your applications. This README will guid

A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

Docopt for Rust (command line argument parser).

THIS CRATE IS UNMAINTAINED This crate is unlikely to see significant future evolution. The primary reason to choose this crate for a new project is if

Quickly build cool CLI apps in Rust.

QuiCLI Quickly build cool CLI apps in Rust. Getting started Read the Getting Started guide! Thanks This is only possible because of all the awesome li

A minimal CLI framework written in Rust
A minimal CLI framework written in Rust

seahorse A minimal CLI framework written in Rust Features Easy to use No dependencies Typed flags(Bool, String, Int, Float) Documentation Here Usage T

Releases(v0.0.6)
  • v0.0.6(Nov 10, 2023)

  • v0.0.5(Nov 9, 2023)

    Changes

    • Documentation improvements
    • Memory handling improvements
    • Reduces complexity of is_time_matching and find_next_occurrence
    • Code cleanup (clippy linting)

    Full Changelog: https://github.com/Hexagon/croner-rust/compare/v0.0.4...v0.0.5

    Source code(tar.gz)
    Source code(zip)
  • v0.0.4(Nov 8, 2023)

    Changes

    • Code refactor
    • More tests
    • Add iterator function iter_from and iter_after
    • Add inline documentation with examples

    Full Changelog: https://github.com/Hexagon/croner-rust/compare/v0.0.3...v0.0.4

    Source code(tar.gz)
    Source code(zip)
  • v0.0.3(Nov 8, 2023)

    Changes

    • Refactored code
    • Add nth weekday (5#2 and 5#L).
    • Add last day of month L.
    • Add internal option dom_and_dow defaulting to false.

    Full Changelog: https://github.com/Hexagon/croner-rust/compare/v0.0.2...v0.0.3

    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(Nov 8, 2023)

Owner
Hexagon
Hexagon
Toggleable cron reminders app for Mac, Linux and Windows

Remind Me Again Remind Me Again Toggleable reminders app for Mac, Linux and Windows Download for Mac, Windows or Linux Dev instructions Get started In

Kasper 42 Apr 22, 2023
🚀 TaskFly - The Fun Cron Alternative

?? TaskFly - The Fun Job Scheduler Daemon Experience a whole new way of scheduling tasks with TaskFly. Representing tasks' urgency with emojis, TaskFl

Zohar Yzgiaev 4 Jul 1, 2023
Blazingly fast interpolated LUT generator and applicator for arbitrary and popular color palettes.

lutgen-rs A blazingly fast interpolated LUT generator and applicator for arbitrary and popular color palettes. Theme any image to your dekstop colorsc

null 12 Jun 16, 2023
Rust-advent - Learning Rust by solving advent of code challenges (Streaming live on Twitch every Monday)

Rust advent ?? ?? Learning Rust by implementing solutions for Advent of Code problems. ?? HEY, we are live-streaming our attempts to solve the exercis

Luciano Mammino 20 Nov 11, 2022
Rust-clippy - A bunch of lints to catch common mistakes and improve your Rust code

Clippy A collection of lints to catch common mistakes and improve your Rust code. There are over 450 lints included in this crate! Lints are divided i

The Rust Programming Language 8.7k Dec 31, 2022
Rust-battery - Rust crate providing cross-platform information about the notebook batteries.

battery Rust crate providing cross-platform information about the notebook batteries. Table of contents Overview Supported platforms Install Examples

svartalf 326 Dec 21, 2022
A Rust-based shell script to create a folder structure to use for a single class every semester. Mostly an excuse to use Rust.

A Rust Course Folder Shell Script PROJECT IN PROGRESS (Spring 2022) When completed, script will create a folder structure of the following schema: [ro

Sebastián Romero Cruz 1 Apr 10, 2022
Rust Imaging Library's Python binding: A performant and high-level image processing library for Python written in Rust

ril-py Rust Imaging Library for Python: Python bindings for ril, a performant and high-level image processing library written in Rust. What's this? Th

Cryptex 13 Dec 6, 2022
FTL Rust Demangler is a command-line tool for demangling symbol names that are mangled with the Rust convention

FTL Rust Demangler is a command-line tool for demangling symbol names that are mangled with the Rust convention. It takes a mangled symbol name as input and returns the demangled name

timetravel3 7 Mar 30, 2023
rpm (Rust project manager) is a tool that helps you to manage your rust projects

rpm rpm (Rust project manager) is a open source tool for managing your rust project in an organized way Installation # make sure you have rust install

Dilshad 4 May 4, 2023