Cronsmith - 终极 Cron 表达式生成器和解析器

Cronsmith 是一个功能强大且多功能的 Java 工具库,旨在以直观、面向对象的方式处理 cron 表达式。它提供了一个高度灵活且用户友好的 API,轻松生成、解析和调度基于 cron 的任务。

Cronsmith 为无缝集成而构建,全面支持 Spring 和 Quartz 的 cron 表达式,确保与广泛使用的调度框架兼容。此外,它通过引入高级模式(例如与 'L'(最后一天)和 'W'(工作日)组合的多个数字)扩展了传统的 cron 语法,提供了更高的调度精度和灵活性。

功能特性

1. 面向对象的 CronExpression构建器

Cronsmith 允许开发者以直观、面向对象的方式构建复杂的 cron 表达式。这种方法便于自定义,避免了手动拼接字符串的麻烦。

Example:
 
@Test
public void test1() {
        CronExpression cronExpression = new CronBuilder()
            .everyMinute(5)
            .second(5)
            .andSecond(10)
            .toSecond(30);
        
        System.out.println(cronExpression.toString());
        assertEquals("5,10-30 */5 * * * ?", cronExpression.toString());
    }

@Test
public void test2() {
        CronExpression cronExpression = new CronBuilder()
            .everyMonth()
            .lastWeekday()
            .hour(10)
            .minute(1)
            .toMinute(15);
        
        System.out.println(cronExpression.toString());
        assertEquals("0 1-15 10 LW * ?", cronExpression.toString());
    }

@Test
public void test3() {
        CronExpression cronExpression = new CronBuilder()
            .year(2025)
            .toYear(2028)
            .everyMonth(2)
            .lastDay()
            .hour(12);
        
        System.out.println(cronExpression.toString());
        assertEquals("0 0 12 L */2 ? 2025-2028", cronExpression.toString());
}

@Test
public void test4() {
    CronExpression cronExpression = new CronBuilder()
        .everyYear(2026, 4)
        .everyMonth(5, 7, 1)
        .day(10).andDay(15).andDay(20).andLastDay(2)
        .everyHour(10, 15, 1)
        .at(10, 0)
        .andSecond(15).andSecond(30).andSecond(45);
    
    System.out.println(cronExpression.toString());
    assertEquals("0,15,30,45 10 10-15 10,15,20,L-2 MAY-JUL ? 2026/4",
            cronExpression.toString());
}

@Test
public void testK() {
        CronExpression cronExpression = new CronBuilder()
                .year(2025).toYear(2030).andYear(2035).toEnd(2)
                .everyMonth(2, 12, 2)
                .dayOfWeek(2, DayOfWeek.TUESDAY)
                .and(3, DayOfWeek.WEDNESDAY).andLastFri()
                .hour(2).andHour(3).andHour(4).toHour(17, 2)
                .minute(0).toMinute(12, 3).andMinute(15).toMinute(40, 2).andMinute(46)
                .andMinute(48).andMinute(50)
                .everySecond(5);
    
        System.out.println(cronExpression.toString());
        assertEquals("*/5 0-12/3,15-40/2,46,48,50 2,3,4-17/2 ? 2/2 TUE#2,WED#3,5L 2025-2030,2035/2",
                cronExpression.toString());
 }

2. Cron 表达式字符串解析与反向生成 CronExpression

Cronsmith 内置了一个强大的解析器,基于 ANTLR 构建,支持将已有的 cron 表达式字符串解析回结构化的 CronExpression 对象。

Example:
@Test
public void test1() {
        String cron = "0 15 10 ? * MON-FRI";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test2() {
        String cron = "0 10,20,30 9-17 L * ?";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test3() {
        String cron = "1,3,5,7,9 3-30/3 12-16 ? * TUE#1";
        CronExpression cronExpression = CRON.parse(cron);
        System.out.println(cronExpression);
        assertEquals(cron, cronExpression.toString());
}

@Test
public void test4() {
    String cron = "5-30/7 0-12/3,15-45/2 2,3,4-17/2 ? JAN-JUL MON-THU/2 2025-2033";
    CronExpression cronExpression = CRON.parse(cron);
    System.out.println(cronExpression);
    assertEquals(cron, cronExpression.toString());
}

Parse Tree:

cron
    second
        secondField
            rangeWithStep
                5
                -
                30
                /
                7
    <missing SPACE>
    minute
        minuteField
            rangeWithStep
                0
                -
                12
                /
                3
        ,
        minuteField
            rangeWithStep
                15
                -
                45
                /
                2
    <missing SPACE>
    hour
        hourField
            2
        ,
        hourField
            3
        ,
        hourField
            rangeWithStep
                4
                -
                17
                /
                2
    <missing SPACE>
    dayOfMonth
        dayOfMonthField
            ?
    <missing SPACE>
    month
        monthField
            monthRange
                monthName
                    JAN
                -
                monthName
                    JUL
    <missing SPACE>
    dayOfWeek
        dayOfWeekField
            weekdayRangeWithStep
                dayOfWeekName
                    MON
                -
                dayOfWeekName
                    THU
                /
                2
    year
        yearField
            yearRange
                2025
                -
                2030
    <EOF>

Retrieve next date and times from CronExpression

public static void main(String[] args) {
   String cron = "0 1,3,5-20 12-16 1,3,20,LW MAR-SEP ? 2026/1";
   CronExpression cronExpression = CRON.parse(cron);
   int N = 1000; // Retrieve 1000 items
   DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   cronExpression.consume(ldt -> {
      System.out.println(ldt.format(dtf));
   }, N);
}

// Console:
// 2026-03-01 12:01:00
// 2026-03-01 12:03:00
// 2026-03-01 12:05:00
// 2026-03-01 12:06:00
// 2026-03-01 12:07:00
// 2026-03-01 12:08:00
// 2026-03-01 12:09:00
// 2026-03-01 12:10:00
// 2026-03-01 12:11:00
// 2026-03-01 12:12:00
// 2026-03-01 12:13:00
// 2026-03-01 12:14:00
// 2026-03-01 12:15:00
// 2026-03-01 12:16:00
// 2026-03-01 12:17:00
// 2026-03-01 12:18:00
// 2026-03-01 12:19:00
// 2026-03-01 12:20:00
// 2026-03-01 13:01:00
// 2026-03-01 13:03:00
// 2026-03-01 13:05:00
// ...

3. 内置调度器

Cronsmith 提供了内置调度器,支持基于 cron 表达式执行指定间隔的任务,轻松实现高效的重复任务调度。

Example: 每 5 秒调度一次任务
private ScheduledExecutorService scheduledExecutorService;

@Before
public void start() {
    scheduledExecutorService =
                Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2);
}

@Test
public void testSchedulerAndRunTenTimes() {
    int N = 10; // Run 10 times
    final CountDownLatch latch = new CountDownLatch(N);
    final AtomicInteger counter = new AtomicInteger();
    
    CronFuture future = new CronBuilder()
        .everySecond(5)
        .scheduler(scheduledExecutorService)
        .setDebuged(false)
        .runTask(() -> {
            System.out.println("Run task_" + counter.incrementAndGet());
            latch.countDown();
        }, N);
    
    try {
        latch.await();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    
    future.cancel(true);
    assertTrue(future.isDone() && counter.get() == N);
}

@After
public void release() {
    scheduledExecutorService.shutdown();
}

4. 高级功能

支持指定年份的某一天

public static void main(String[] args) {
   int N = 1000;
   DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   new CronBuilder().setZoneId(ZoneId.of("UTC")).year(2025).day(208).andDay(330).toLastDay()
                .at(12, 0).consume(ldt -> {
                    System.out.println(ldt.format(dtf));
                }, N);
}
// Console: 
// 2025-07-27 12:00:00
// 2025-11-26 12:00:00
// 2025-11-27 12:00:00
// 2025-11-28 12:00:00
// 2025-11-29 12:00:00
// 2025-11-30 12:00:00
// 2025-12-01 12:00:00
// 2025-12-02 12:00:00
// 2025-12-03 12:00:00
// 2025-12-04 12:00:00
// 2025-12-05 12:00:00
// 2025-12-06 12:00:00
// ...

支持指定年份的某周

public static void main(String[] args) {
    int N = 1000;
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    new CronBuilder().setZoneId(ZoneId.of("UTC")).everyYear().week(40).andWeek(45).Mon().toFri()
                .at(12, 0).consume(ldt -> {
                    System.out.println(ldt.format(dtf));
                }, N);
}
// Console: 
// 2025-09-29 12:00:00
// 2025-09-30 12:00:00
// 2025-10-01 12:00:00
// 2025-10-02 12:00:00
// 2025-10-03 12:00:00
// 2025-11-03 12:00:00
// 2025-11-04 12:00:00
// 2025-11-05 12:00:00
// 2025-11-06 12:00:00
// 2025-11-07 12:00:00
// 2026-09-28 12:00:00
// 2026-09-29 12:00:00
// 2026-09-30 12:00:00
// 2026-10-01 12:00:00
// 2026-10-02 12:00:00
// ...

安装

支持 Jdk1.8 或更高版本

在 Maven 项目中添加以下依赖:

<dependency>
    <groupId>com.github.paganini2008</groupId>
    <artifactId>cronsmith</artifactId>
    <version>1.0.0-beta</version>
</dependency>

Gradle 项目中添加:

dependencies {
    implementation 'com.github.paganini2008:cronsmith:1.0.0'
}

快速开始

  1. 在项目中添加 Cronsmith 依赖。
  2. 使用 CronBuilder 创建复杂的 cron 表达式。
  3. 通过 CRON.parse() 解析已有的 cron 表达式。
  4. 使用内置调度器调度任务。

野猪飞舞
26 声望0 粉丝

酷爱软件开发,致力于原创软件开发,而不是应用级开发,热衷于造轮子,而不是重复造轮子,原创不易,多多支持!