Cron 表达式反解析

Cron 表达式反解析

Cron 表达式是一种标准的时间表达式,用来描述定时任务的执行时间,通常被用于批处理、系统定时任务等场景中。由于其简洁、灵活的特性,Cron 表达式已经成为了定时任务时间设定的事实标准,深受开发者的喜爱和使用。

然而,在某些情况下,我们需要根据 Cron 表达式来计算下一次的执行时间、反解析 Cron 表达式以确定它具体表示的时间,这时候就需要使用 Cron 表达式反解析的技巧了。在本文中,我们将会全面介绍 Cron 表达式反解析的原理和相关实现技巧。

Cron 表达式语法

在了解 Cron 表达式反解析的原理之前,我们先来回顾一下 Cron 表达式的基本语法:

*    *    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    │    │
│    │    │    │    │    │    └─年份(可选)
│    │    │    │    │    └───星期(0-6,0 表示星期日,可用英文缩写表示,也可以使用英文单词)
│    │    │    │    └────月份(1-12 或者 JAN-DEC,可用英文缩写表示,也可以使用英文单词)
│    │    │    └────────日(1-31)
│    │    └─────────────小时(0-23)
│    └──────────────────分(0-59)
└───────────────────────秒(0-59)

如上,它有 7 个字段,分别表示秒、分、小时、日、月、周、年,每个字段可以由数字、星号、斜杆、连字符、逗号、问号等符号进行组合,以描述特定的时间点或时间段。

比如,0 0 2 ? * 1 表示每周一早上 2 点启动任务,0 0/5 14 * * ? 表示每天下午 2 点到晚上 2 点 55 分,每隔 5 分钟启动任务。



Cron 表达式反解析原理

在进行 Cron 表达式反解析的时候,一般分为两步:

  1. 根据 Cron 表达式计算出指定时间点
  2. 将指定时间点转换成 Cron 表达式

对于第一步,我们可以通过一些开源的工具或者自己编写代码实现。比如,CronSequenceGenerator 这个类就是 Spring 中提供的一个计算 Cron 表达式的工具。

CronSequenceGenerator generator = new CronSequenceGenerator("0 0 2 ? * 1");
Date next = generator.next(new Date());
System.out.println(next);
// 输出:Mon Jun 07 02:00:00 CST 2021

这里通过 CronSequenceGenerator 类,以“0 0 2 ? * 1”为参数创建了一个 Cron 表达式生成器,然后调用 next() 方法计算出下一个满足条件的时间点,并输出了计算结果。

对于第二步,我们需要按照 Cron 表达式的语法规则逐一研究指定的时间点,并找到可以表达这个时间点的最精简表达式。比如,对于指定的时间点 Mon Jun 07 02:00:00 CST 2021,我们可以根据 Cron 表达式的语法规则来进行分析:

  1. 根据日期和时间计算出每个字段的数值
   秒:0   分:0
   时:2
   日:无需计算(?)
   月:6
   周:2(星期一)
   年:2021
   ```

2. 根据数值组合出最精简的 Cron 表达式

```bash
   0 0 2 ? * 2
   ```

   这个表达式表示:秒为 0,分为 0,时为 2,日为无需计算(`?`),月为 6,周为 2(星期一),年为 2021。

需要注意的是,反解析 Cron 表达式的过程是不唯一的,同一个时间点可能会有多种表达方式。而且,Cron 表达式并不直观,对于一些时间点,可能会有多个合理的表达方式,我们可以根据实际需求选择最合适的表达方式。

## 代码实现

下面,我们来看一下如何用 Java 代码实现 Cron 表达式反解析的功能。

### 依赖

需要依赖以下两个库:

```groovy
implementation 'com.cronutils:cron-utils:9.1.0'
implementation 'joda-time:joda-time:2.10.12'

根据时间点反解析 Cron 表达式

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.cronutils.descriptor.CronDescriptor;
import com.cronutils.model.Cron;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;

public class CronExpParser {

    public static String generateCronExpression(String datetimeString, String cronExpressionString) {
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        DateTime dateTime = DateTime.parse(datetimeString, formatter);
        // 转换为 UTC 时间
        DateTime utcDateTime = dateTime.withZone(DateTimeZone.UTC);
        CronDescriptor descriptor = CronDescriptor.instance(Locale.CHINA);
        CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
        Cron cron = parser.parse(cronExpressionString);
        String computedExpression = descriptor.describe(cron).replaceAll(" ", "");
        return utcDateTime.toString("ss mm HH dd MM ? yyyy", Locale.CHINA).replaceFirst("\\d{4}$",
                computedExpression.substring(computedExpression.lastIndexOf('/') + 1));
    }
}

这里 generateCronExpression 是反解析 Cron 表达式的核心方法。它接受两个参数:一个是时间点字符串(格式为 yyyy-MM-dd HH:mm:ss),一个是待反解析的 Cron 表达式字符串。

该方法使用 Joda-Time 库将时间点字符串转换成 DateTime 对象,并把它转换成 UTC 时间。然后使用 cron-utils 库中的 CronParser 类来解析 Cron 表达式,并使用 CronDescriptor 类生成一个描述字符串。最后通过字符串操作拼接出反解析后的 Cron 表达式。

注意,这里我们使用了 Locale.CHINA 来设置语言环境,在生成描述字符串时更符合中文语境。

指定时区的实现

上面的实现默认将时间转换为 UTC 时间进行计算。如果需要指定时区来计算,我们只需要传入时区信息即可:

public static String generateCronExpressionWithTimeZone(String datetimeString, String cronExpressionString,
        String timeZoneString) {
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withZone(DateTimeZone.UTC);
    DateTime dateTime = formatter.parseDateTime(datetimeString);
    DateTimeZone timeZone = DateTimeZone.forID(timeZoneString);
    DateTimeZone.setDefault(timeZone);
    CronDescriptor descriptor = CronDescriptor.instance(Locale.CHINA);
    CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
    Cron cron = parser.parse(cronExpressionString);
    String computedExpression = descriptor.describe(cron).replaceAll(" ", "");
    return dateTime.withZone(timeZone).toString("ss mm HH dd MM ? yyyy", Locale.CHINA).replaceFirst("\\d{4}$",
            computedExpression.substring(computedExpression.lastIndexOf('/') + 1));
}

在这个方法中,我们新增了一个 `timeZoneString` 参数来指定时间所在的时区。我们使用`DateTimeZone` 类将时间转换为指定时区,在生成 Cron 表达式之前通过 `DateTimeZone.setDefault()` 将默认时区设置为指定时区。

### 根据 Cron 表达式计算下一次执行时间

```java
public static String getNextExecutionTime(String cronExpressionString, String datetimeString) {
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withZone(DateTimeZone.UTC);
    DateTime dateTime = formatter.parseDateTime(datetimeString);
    CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
    ZonedDateTime zonedDateTime = dateTime.toDateTime(DateTimeZone.UTC).toInstant().atZone(ZoneId.systemDefault());
    ZonedDateTime nextZonedDateTime = ExecutionTime.forCron(parser.parse(cronExpressionString)).nextExecution(zonedDateTime).get();
    return nextZonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}

代码中的 getNextExecutionTime 方法用于计算下一次执行时间。它接受两个参数,一个是 Cron 表达式字符串,一个是时间点字符串。该方法先将时间点字符串转换成 DateTime 对象再转换成 ZonedDateTime 对象,然后使用 cron-utils 库中的 ExecutionTime 类来计算出下一次执行的时间点。

计算出的时间点是一个 ZonedDateTime 对象,可以通过在该对象上应用格式化来获取它的字符串表示形式。

结论

Cron 表达式反解析是一项常见的开发任务,在实际项目中常常会用到。本文介绍了 Cron 表达式的语法规则和反解析原理,并提供了 Java 代码实现。我们可以根据自己的需求及具体场景选择合适的实现方式,便于实现更加精准、灵活的定时任务。


赞(0)
未经允许不得转载:极客笔记 » Cron 表达式反解析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
Linux系统管理命令
Linux 一次性计划任务atLinux 周期性计划任务crontabLinux 为脚本加锁flockLinux 发送信号命令killLinux 查找文件内容grepLinux 查找符合条件的文件find
Linux登录退出关机重启命令
login命令 用户登录系统logout命令 退出登录Shellnologin命令 限制用户登录exit命令 退出shellsulogin命令 单用户登录rlogin命令 远程登录poweroff命令 关闭系统ctrlaltdel命令 设置按Ctrl+Alt+Del组合键功能shutdown命令 关闭或重启Linux系统halt命令 关闭系统reboot命令 重启Linux系统init命令 切换系统运行级别runlevel命令 输出以前和当前运行级别telinit命令 更改系统运行级别
Linux获取帮助命令
help命令 查看内部Shell命令帮助信息man命令 显示在线手册页manpath命令 查看和设置man手册页的查询路径Linux info命令Linux pinfo命令
Linux文本编辑器命令
Linux vi命令Linux nano命令Linux view命令Linux ex命令Linux ed命令Linux red命令Linux emacs命令
Linux目录和文件操作命令
Linux pwd命令Linux cd命令Linux ls命令Linux dir命令Linux dirs命令Linux touch命令Linux mkdir命令Linux rmdir命令Linux cp命令Linux mv命令Linux rm命令Linux install命令Linux tmpwatch命令Linux file命令Linux du命令Linux wc命令Linux tree命令Linux cksum命令Linux md5sum命令Linux sum命令Linux dirname命令Linux mkfifo命令Linux mktemp命令Linux ln命令Linux sln命令Linux lndir命令Linux link命令Linux unlink命令Linux basename命令Linux pathchk命令Linux symlinks命令Linux stat命令Linux rcp命令Linux fsview命令Linux mc命令
Linux显示文本文件内容命令
Linux cat命令Linux more命令Linux less命令Linux head命令Linux tail命令Linux nl命令Linux tac命令Linux rev命令Linux fold命令Linux fmt命令Linux expand命令Linux pr命令
Linux文件处理命令
Linux sort命令Linux uniq命令Linux cut命令Linux comm命令Linux diff命令Linux join命令Linux diff3命令Linux cmp命令Linux colrm命令Linux paste命令Linux tr命令Linux split命令Linux csplit命令Linux tee命令Linux unexpand命令Linux patch命令Linux awk命令Linux sed命令Linux od命令
Linux字符串、文件和命令查找命令
Linux grep命令Linux egrep命令Linux fgrep命令Linux find命令Linux updatedb命令Linux locate命令Linux whereis命令Linux whatis命令Linux apropos命令Linux which命令Linux look命令
Linux日期和时间命令
Linux cal命令Linux date命令Linux hwclock命令Linux clock命令Linux clockdiff命令Linux zdump命令Linux rdate命令Linux sleep命令
Linux数字计算命令
Linux bc命令Linux dc命令Linux expr命令
Linux Shell相关命令
Linux command命令Linux exec命令Linux bash命令Linux builtin命令Linux enable命令Linux source命令Linux mksh命令Linux suspend命令Linux sushell命令Linux shopt命令Linux rsh命令Linux ulimit命令Linux history命令Linux alias命令Linux unalias命令Linux eval命令Linux fc命令Linux declare命令Linux export命令Linux set命令Linux unset命令Linux env命令Linux read命令Linux readonly命令Linux test命令Linux false命令
Linux 程序编译相关命令
Linux gcc命令Linux gdbserver命令Linux cmake命令Linux indent命令Linux protoize命令Linux unprotoize命令Linux gcov命令Linux find2perl命令Linux as命令Linux php命令Linux perl命令Linux gdb命令Linux autoupdate命令Linux autoheader命令Linux autoreconf命令Linux autoscan命令Linux autoconf命令
Linux用户管理命令
Linux useradd命令Linux adduser命令Linux lnewusers命令Linux usermod命令Linux userdel命令Linux groupadd命令Linux groupmod命令Linux groupdel命令Linux passwd命令Linux gpasswd命令Linux chfn命令Linux chsh命令Linux pwck命令Linux newgrp命令Linux finger命令Linux groups命令Linux id命令Linux grpck命令Linux grpconv命令Linux grpunconv命令Linux groupmems命令Linux userinfo命令Linux userpasswd命令Linux vigr命令Linux vipw命令Linux newusers命令Linux chpasswd命令Linux pwconv命令Linux pwunconv命令Linux chage命令Linux su命令Linux visudo命令Linux sudo命令Linux sudoedit命令Linux sudoreplay命令Linux w命令Linux who命令Linux whoami命令Linux logname命令Linux users命令Linux last命令Linux lastb命令Linux lastlog命令Linux rwho命令
Linux文件、目录权限和属性命令
Linux chmod命令Linux chown命令Linux chgrp命令Linux umask命令Linux getfacl命令Linux setfacl命令Linux chacl命令Linux lsattr命令Linux chattr命令
Linux归档与压缩命令
Linux tar命令Linux gzip命令Linux gunzip命令Linux zcmp命令Linux zdiff命令Linux zforce命令Linux zip命令Linux unzip命令Linux zcat命令Linux zgrep命令Linux zipgrep命令Linux zipinfo命令Linux zipsplit命令Linux zless命令Linux zmore命令Linux bzip2命令Linux bunzip2命令Linux bzcat命令Linux bzcmp命令Linux bzdiff命令Linux bzgrep命令Linux bzip2recover命令Linux bzless命令Linux bzmore命令Linux compress命令Linux uncompres命令Linux znew命令Linux xz命令Linux xzcat命令Linux xzcmp命令Linux xzdiff命令Linux xzdec命令Linux xzgrep命令Linux xzless命令Linux xzmore命令Linux tgz命令Linux gzexe命令
Linux 软件包管理相关命令
Linux rpm命令Linux rpmargs命令Linux rpmbuild命令Linux rpmdiff命令Linux rpmelfsym命令Linux rpmfile命令Linux rpmlint命令Linux rpm2cpio命令Linux yum命令Linux yum-builddep命令Linux yum-complete-transaction命令Linux yumdb命令Linux yum-debug-dump命令Linux yum-debug-restore命令Linux yumdownloader命令Linux yum-groups-manager命令Linux yum-config-manager命令
Linux 磁盘分区相关命令
Linux fdisk命令Linux parted命令Linux cfdisk命令Linux partx命令Linux sfdisk命令Linux delpart命令Linux partprobe命令
Linux 文件系统管理相关命令
Linux mkfs命令Linux mke2fs命令Linux mkfs.ext4命令Linux mkfs.ext3命令Linux mkfs.ext2命令Linux mkdosfs命令Linux mkfs.vfat命令Linux mkfs.msdos命令Linux fdformat命令Linux mount命令Linux umount命令Linux df命令Linux mountpoint命令Linux e2label命令Linux dumpe2fs命令Linux tune2fs命令Linux findfs命令Linux blkid命令Linux e2image命令Linux fsck命令Linux e2fsck命令Linux fsadm命令Linux mkswap命令Linux swapon命令Linux swapoff命令Linux volname命令Linux quotacheck命令Linux edquota命令Linux quotaon命令Linux quota命令Linux repquota命令Linux quotastats命令Linux setquota命令Linux quotaoff命令Linux warnquota命令Linux convertquota命令
Linux LVM和RAID管理命令
Linux pvcreate命令Linux pvscan命令Linux pvdisplay命令Linux vgcreate命令Linux vgscan命令Linux vgdisplay命令Linux vgreduce命令Linux vgextend命令Linux lvscan命令Linux lvdisplay命令Linux lvextend命令Linux resize2fs命令Linux lvremove命令Linux vgchange命令Linux vgremove命令Linux pvremove命令Linux pvchange命令Linux pvck命令Linux pvresize命令Linux pvmove命令Linux pvs命令Linux vgcfgbackup命令Linux vgcfgrestore命令Linux vgchange命令Linux vgconvert命令Linux vgexport命令Linux vgimport命令Linux vgimportclone命令Linux vgmerge命令Linux vgmknodes命令Linux vgrename命令Linux vgs命令Linux vgsplit命令Linux lvchange命令Linux lvmconf命令Linux lvmdiskscan命令Linux lvmdump命令Linux lvmetad命令Linux lvreduce命令Linux lvrename命令Linux lvresize命令Linux lvs命令Linux mdadm命令Linux grub-md5-crypt命令Linux grub-install命令Linux grub命令Linux grub-crypt命令
Linux 进程和服务管理命令
Linux ps命令Linux top命令Linux pgrep命令Linux pidof命令Linux pstree命令Linux kill命令Linux killall命令Linux pkill命令Linux timeout命令Linux skill命令Linux wait命令Linux fuser命令Linux nice命令Linux renice命令Linux nohup命令Linux pmap命令Linux lsof命令Linux ntsysv命令Linux chkconfig命令Linux service命令Linux bg命令Linux fg命令Linux jobs命令Linux initctl命令
Linux 任务计划相关命令
Linux crontab命令Linux at命令Linux atq命令Linux atrm命令Linux atrun命令Linux batch命令Linux anacron命令Linux watch命令
Linux 备份与还原相关命令
Linux mkisofs命令Linux isosize命令Linux dump命令Linux restore命令Linux cpio命令Linux dd命令Linux wodim命令Linux cdrecord命令Linux dvdrecord命令Linux cdrwtool命令
Linux 模块和内核管理命令
Linux lsmod命令Linux get_module命令Linux modinfo命令Linux insmod命令Linux modprobe命令Linux rmmod命令Linux depmod命令Linux sysctl命令Linux kexec命令Linux slabtop命令Linux dmesg命令Linux make命令
Linux 日志模块命令
Linux logwatch命令Linux logger命令Linux logsave命令Linux logresolve命令
Linux 硬件管理相关命令
Linux lscpu命令Linux nproc命令Linux chcpu命令Linux cpuspeed命令Linux free命令Linux lspci命令Linux setpci命令Linux lsscsi命令Linux hdparm命令Linux eject命令Linux lsusb命令Linux usb-devices命令Linux lspcmcia命令Linux pccardctl命令Linux setserial命令Linux lssubsys命令Linux lpinfo命令Linux losetup命令Linux blockdev命令Linux dmidecode命令Linux systool命令Linux mev命令Linux loadkeys命令Linux dumpkeys命令Linux minicom命令Linux arch命令Linux sync命令
Linux SELinux管理相关命令
Linux sestatus命令Linux getenforce命令Linux setenforce命令Linux getfattr命令Linux chcon命令Linux matchpathcon命令Linux fixfiles命令Linux restorecon命令Linux seinfo命令Linux sesearch命令Linux getsebool命令Linux setsebool命令Linux semodule命令
Linux 审计系统相关命令
Linux auditctl命令Linux aureport命令Linux ausearch命令Linux autrace命令Linux audit-viewer命令
Linux 设备管理相关命令
Linux udevadm info命令Linux mknod命令Linux MAKEDEV命令Linux lsblk命令
Linux 性能监控命令
Linux sar命令Linux iostat命令Linux iotop命令Linux mpstat命令Linux vmstat命令Linux tload命令Linux time命令Linux uptime命令Linux ipcs命令Linux ipcrm命令Linux lslk命令
Linux X Window命令
Linux xhost命令Linux xinit命令Linux xlsclients命令Linux xlsfonts命令Linux resize命令Linux startx命令Linux screen命令Linux xset命令Linux xauth命令
Linux 打印和传真命令
Linux lpr命令Linux lpq命令Linux lprm命令Linux lpstat命令Linux cupsaccept命令Linux cupsreject命令Linux cupsenable命令Linux cupsdisable命令Linux cancel命令Linux lp命令Linux lpadmin命令Linux efax命令
Linux 终端命令
Linux tty命令Linux consoletype命令Linux fgconsole命令Linux mingetty命令Linux vlock命令Linux stty命令Linux tset命令Linux open命令Linux reset命令Linux securetty命令Linux tput命令
Linux 密码和证书管理命令
Linux pwdhash命令Linux mkpasswd命令Linux keytool命令Linux certutil命令Linux vncpasswd命令Linux ssh-keygen命令Linux htpasswd命令Linux htdigest命令Linux ntp-keygen命令Linux slappasswd命令Linux rndc-confgen命令Linux openssl:OpenSSL命令
Linux 系统故障排错命令
Linux mkbootdisk命令Linux chroot命令Linux badblocks命令Linux mkinitrd命令Linux switch_root命令Linux mkdumprd命令
Linux 网络命令
Linux traceroute命令Linux mii-tool命令Linux ifconfig命令
Linux Zip
Linux zip命令详解Linux zip压缩Linux zip解压Linux Zip文件解压教程Linux zip压缩文件Linux zip压缩文件夹
Linux chmod
Linux chmod命令详解Linux chmod 777整个目录Linux chmod+x无效Linux chmod改属性
lsblk
lsblk 命令详解lsblk 和fdisk看到的盘不一样lsblk 和 df -h的区别lsblk -f命令解决lsblk命令找不到的问题lsblk 命令详解
Linux ps
Linux ps命令Linux ps参数说明Linux ps命令输出结果排序
Linux touch
Linux touch命令Linux Touch怎么设置Linux touch提示权限不够Linux touch和mkdirLinux touch命令修改文件时间
Cron 表达式
Cron 表达式Cron 表达式每天12点执行Java定时任务cron表达式Vue Cron表达式JS Cron表达式定时任务cron表达式详解Spring定时任务Cron表达式Linux cron表达式Quartz Cron表达式Cron 表达式反解析Cron 表达式Cron 时间表达式Cron 表达式解析Cron 表达式每秒执行一次Cron 表达式每分钟执行一次Cron 表达式每10分钟执行一次Cron 表达式每小时执行一次Cron 表达式每年执行一次Cron表达式每天0点执行一次