Rust的cron表达式解析库cron-parser的使用,支持高性能定时任务调度与时间解析
Rust的cron表达式解析库cron-parser的使用,支持高性能定时任务调度与时间解析
cron-parser是一个用于解析cron表达式并支持时区的Rust库。
示例用法
use chrono::{TimeZone, Utc};
use chrono_tz::Europe::Lisbon;
use cron_parser::parse;
fn main() {
// 解析每5分钟执行一次的cron表达式
if let Ok(next) = parse("*/5 * * * *", &Utc::now()) {
println!("when: {}", next);
}
// 使用自定义时间戳解析闰年表达式
if let Ok(next) = parse("0 0 29 2 *", &Utc.timestamp(1893456000, 0)) {
println!("next leap year: {}", next);
assert_eq!(next.timestamp(), 1961625600);
}
// 测试复杂表达式
assert!(parse("2-3,9,*/15,1-8,11,9,4,5 * * * *", &Utc::now()).is_ok());
// 测试不支持的表达式(星期几不支持*/Day格式)
assert!(parse("* * * * */Fri", &Utc::now()).is_err());
// 使用自定义时区
assert!(parse("*/5 * * * *", &Utc::now().with_timezone(&Lisbon)).is_ok());
}
Cron表达式格式
# ┌───────────────────── 分钟 (0 - 59)
# │ ┌─────────────────── 小时 (0 - 23)
# │ │ ┌───────────────── 日 (1 - 31)
# │ │ │ ┌─────────────── 月 (1 - 12)
# │ │ │ │ ┌───────────── 周几 (0 - 6 或 Sun - Sat)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * * <要执行的命令>
字段 | 是否必填 | 允许值 | 允许的特殊字符 |
---|---|---|---|
分钟 | 是 | 0-59 | * , - / |
小时 | 是 | 0-23 | * , - / |
日 | 是 | 1-31 | * , - / |
月 | 是 | 1-12 | * , - / |
周几 | 是 | 0-6或Sun-Sat | * , - / |
对于周几字段,当使用星期几(Sun-Sat)时,表达式
*/Day
不支持,应该使用数字。例如*/Wed
=*/3
表示每3天运行一次(周日、周三、周六)。
特殊字符含义:
*
任何值,
值列表分隔符-
值范围/
步长值
范围步长
支持带步长的范围表达式,例如:
0 12-18/3 * * * # 从12点到18点,每3小时一次
或者从1点开始每6小时:
0 1/6 * * *
依赖配置
依赖chrono
crate。
在Cargo.toml
中添加:
[dependencies]
chrono = "^0.4"
cron-parser = "*"
完整示例
获取未来10个闰年的日期:
use chrono::{DateTime, Utc};
use cron_parser::parse;
fn main() {
// 获取当前UTC时间
let now = Utc::now();
let mut crons = Vec::<DateTime<Utc>>::new();
// 解析闰年表达式(2月29日)
let mut next = parse("0 0 29 2 *", &now).unwrap();
// 获取未来10个闰年日期
for _ in 0..10 {
next = parse("0 0 29 2 *", &next).unwrap();
crons.push(next);
}
// 打印结果
for x in crons {
println!("{} - {}", x, x.timestamp());
}
}
输出示例:
2024-02-29 00:00:00 UTC - 1709164800
2028-02-29 00:00:00 UTC - 1835395200
2032-02-29 00:00:00 UTC - 1961625600
2036-02-29 00:00:00 UTC - 2087856000
2040-02-29 00:00:00 UTC - 2214086400
2044-02-29 00:00:00 UTC - 2340316800
2048-02-29 00:00:00 UTC - 2466547200
2052-02-29 00:00:00 UTC - 2592777600
2056-02-29 00:00:00 UTC - 2719008000
2060-02-29 00:00:00 UTC - 2845238400
另一个完整示例:定时任务调度器
use chrono::{DateTime, Utc, Duration};
use cron_parser::parse;
fn main() {
// 定义cron表达式(每小时的第30分钟执行)
let cron_expr = "30 * * * *";
let mut next_run = parse(cron_expr, &Utc::now()).unwrap();
println!("Next run at: {}", next_run);
// 模拟调度器运行5次
for i in 1..=5 {
// 计算当前时间和下次运行时间的时间差
let now = Utc::now();
let wait_time = if next_run > now {
next_run - now
} else {
Duration::seconds(0)
};
println!("[{i}] Waiting {} seconds...", wait_time.num_seconds());
// 这里可以添加实际要执行的任务代码
// 计算下一次运行时间
next_run = parse(cron_expr, &next_run).unwrap();
println!("Next run at: {}", next_run);
}
}
1 回复
Rust的cron表达式解析库cron-parser使用指南
cron-parser
是一个用于解析cron表达式并计算下次执行时间的Rust库,非常适合需要高性能定时任务调度的应用场景。
基本功能
- 解析标准cron表达式
- 计算下一次/上一次匹配的时间
- 支持秒级精度(6段式cron表达式)
- 支持常见的cron表达式扩展
安装
在Cargo.toml
中添加依赖:
[dependencies]
cron-parser = "0.3"
基本使用方法
解析cron表达式
use cron_parser::parse;
fn main() {
// 解析标准的5段式cron表达式
let schedule = parse("30 4 * * *").unwrap();
// 解析包含秒的6段式cron表达式
let precise_schedule = parse("0 30 4 * * *").unwrap();
}
计算下次执行时间
use cron_parser::parse;
use chrono::{Local, TimeZone};
fn main() {
let schedule = parse("30 4 * * *").unwrap();
let now = Local::now();
// 计算下次执行时间
if let Some(next_time) = schedule.next_after(&now) {
println!("下次执行时间: {}", next_time);
}
// 也可以计算前一次执行时间
if let Some(prev_time) = schedule.prev_before(&now) {
println!("上次执行时间: {}", prev_time);
}
}
高级用法
检查时间是否匹配cron表达式
use cron_parser::parse;
use chrono::Local;
fn main() {
let schedule = parse("0 */5 * * * *").unwrap(); // 每5分钟
let now = Local::now();
if schedule.matches(&now) {
println!("当前时间匹配cron表达式");
}
}
迭代所有匹配时间
use cron_parser::parse;
use chrono::{Local, Duration};
fn main() {
let schedule = parse("0 0 * * *").unwrap(); // 每天午夜
let start = Local::now();
let end = start + Duration::days(7);
// 获取接下来一周内所有匹配时间
let occurrences: Vec<_> = schedule.after(&start).until(&end).collect();
for time in occurrences {
println!("匹配时间: {}", time);
}
}
注意事项
-
cron-parser
支持标准的5段和6段(带秒)格式:* * * * *
(分 时 日 月 周)* * * * * *
(秒 分 时 日 月 周)
-
支持特殊字符:
*
- 任意值,
- 值列表分隔符-
- 范围/
- 步长
-
月份和周几可以使用名称缩写(JAN, FEB… 或 MON, TUE…)
性能提示
cron-parser
经过优化,适合高性能场景。对于频繁调用的场景,建议:
- 重复使用已解析的Schedule对象,避免重复解析
- 考虑使用
lazy_static
缓存常用表达式
#[macro_use]
extern crate lazy_static;
use cron_parser::parse;
use chrono::Local;
lazy_static! {
static ref HOURLY_SCHEDULE: cron_parser::Schedule = {
parse("0 * * * *").unwrap()
};
}
fn main() {
let now = Local::now();
if let Some(next) = HOURLY_SCHEDULE.next_after(&now) {
println!("下一个整点: {}", next);
}
}
完整示例demo
下面是一个完整的示例,展示如何使用cron-parser构建一个简单的定时任务调度器:
use cron_parser::parse;
use chrono::{Local, Duration};
use std::thread;
use std::time::Duration as StdDuration;
fn main() {
// 解析一个每5分钟执行一次的cron表达式
let schedule = parse("0 */5 * * * *").expect("无效的cron表达式");
println!("开始定时任务调度器,每5分钟执行一次...");
println!("当前时间: {}", Local::now());
loop {
let now = Local::now();
// 计算下次执行时间
if let Some(next_time) = schedule.next_after(&now) {
println!("下次执行时间: {}", next_time);
// 计算需要等待的时间
let wait_duration = next_time - now;
let wait_seconds = wait_duration.num_seconds();
// 等待直到下次执行时间
println!("等待 {} 秒...", wait_seconds);
thread::sleep(StdDuration::from_secs(wait_seconds as u64));
// 执行任务
println!("执行任务: {}", Local::now());
perform_task();
} else {
println!("没有下次执行时间,退出");
break;
}
}
}
fn perform_task() {
// 这里是你的定时任务逻辑
println!("执行定时任务...");
// 模拟任务执行时间
thread::sleep(StdDuration::from_secs(1));
}
这个示例演示了如何:
- 解析cron表达式
- 计算下次执行时间
- 等待直到执行时间到达
- 执行定时任务
- 循环执行上述过程
你可以根据需要修改cron表达式和任务逻辑来适应不同的定时任务需求。