java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间)
定时任务需求
在一个特殊的项目需求中,我们设计一个定时任务,并算出它所有的执行时间点。
1.有开始时间和结束时间。
2.每周一、四、六执行(动态参数) 执行的时和分HH:mm(动态参数)
3.隔n周执行(动态参数)
4.算每次执行时间。
程序设计
参数 | 类型 | 说明 |
---|---|---|
定时任务开始时间 | startTime | yyyy-MM-dd |
定时任务结束时间 | endTime | yyyy-MM-dd |
执行时间 | executeTime | HH:mm |
周几执行列表 | weekList: [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六] | cron中 [1,2,3,4,5,6,7] 代表:[周日,周一,周二,周三,周四,周五,周六] |
隔几周执行一次 | interval | 数字n |
依赖引入
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
程序
一、计算开始时间那周的周一时间
考虑隔周执行,一定要以开始时间那个周的周一为起点,否则时间会算错。
/**
* 开始时间点的周一时间
* @param startDate
* @return
*/
public static Date getMonday(Date startDate){
/**
* 计算给出时间的周一时间
*/
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
// 将小时、分钟、秒和毫秒字段设置为0
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// 将日期设置为本周第一天(默认为周日)的前一天(即周一)
calendar.add(Calendar.DAY_OF_WEEK, Calendar.MONDAY - calendar.get(Calendar.DAY_OF_WEEK));
// 输出周一0点的时间
return calendar.getTime();
}
二、根据executeTime和weekList.get(n),计算每个cron表达式。
/**
*计算cron表达式
*@param executeTime 执行时间 HH:mm
* @param week 周几
* @return cron表达式
* @throws ParseException
*/
public static String createCronStr(String executeTime, Integer week) {
String weekStr = String.valueOf(week + 1);
// 设置cron表达式,周三,下午3点30分执行
String cronExpression = "0 %1$s %2$s ? * %3$s";
String[] times = executeTime.split(":");
String hour = times[0];
String minute = times[1];
return String.format(cronExpression, minute, hour, weekStr);
}
三、根据一和二得出的cron表达式和开始时间的那周的周一时间,计算每次定时任务执行的第一次时间。
/**
* 计算下次执行时间
* @param cronExpression cron
* @param startTime2 开始时间(开始时间的周一时间)
* @return
* @throws ParseException
*/
public static Date getNextExecutionTime(String cronExpression, Date startTime2) throws ParseException {
CronExpression cron = new CronExpression(cronExpression);
Date nextExecutionTime = cron.getNextValidTimeAfter(startTime2);
System.out.println("下次执行时间: " + nextExecutionTime);
return nextExecutionTime;
}
四、计算所有执行时间
/**
*
* @param startTime 定时任务开始时间 yyyy-MM-dd
* @param endTime 定时任务结束时间 yyyy-MM-dd
* @param executeTime 执行时间 HH:mm
* @param weekList 周几执行列表 [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六]
* @param interval 隔几周执行一次
* @return
*/
public static List<String> getExecuteTimeList(String startTime, String endTime, String executeTime, List<Integer> weekList, int interval) {
List<String> list = new ArrayList<>();
try {
String startStr = startTime + executeTime;
String endStr = endTime + executeTime;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm");
Date endDate = dateFormat.parse(endStr);
Date startDate = dateFormat.parse(startStr);
Date now = new Date();
//设置日期过期,返回空
if (now.getTime() > endDate.getTime()) {
return new ArrayList<>();
}
interval++;
for (Integer week : weekList) {
String cronExpression = createCronStr(executeTime, week);
if (StringUtils.isBlank(cronExpression)) {
continue;
}
Date startTime2 = getMonday(startDate);
Date nextExecutionTime = getNextExecutionTime(cronExpression,startTime2);
int add = 0;
Date nownext = nextExecutionTime;
while (nownext.getTime() <= endDate.getTime()) {
nownext = new Date(nextExecutionTime.getTime() + add * interval * 7 * 24 * 60 * 60 * 1000L);
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String str = dateFormat2.format(nownext);
if (nownext.getTime() <= endDate.getTime() && nownext.getTime()>=startDate.getTime()) {
list.add(str);
}
add++;
}
}
Collections.sort(list);
} catch (ParseException e) {
System.out.println("解析异常: " + e.getMessage());
e.printStackTrace();
}
return list;
}
五、测试
计算2024-06-15到2026-12-31,每周一、四、六的20:40,并隔一周执行一次的所有执行时间
public static void main(String[] args) {
List<Integer> week = new ArrayList<>();
week.add(1);
week.add(4);
week.add(6);
long start = System.currentTimeMillis();
List<String> list = getExecuteTimeList("2024-06-15", "2026-12-31", "20:40", week, 1);
long end = System.currentTimeMillis();
System.out.println(end - start + " ms");
for(String element : list) {
System.out.println(element);
}
}
六、测试结果
下次执行时间: Mon Jun 10 20:40:00 CST 2024
下次执行时间: Thu Jun 13 20:40:00 CST 2024
下次执行时间: Sat Jun 15 20:40:00 CST 2024
74 ms
2024-06-15 20:40
2024-06-24 20:40
2024-06-27 20:40
2024-06-29 20:40
2024-07-08 20:40
2024-07-11 20:40
2024-07-13 20:40
2024-07-22 20:40
2024-07-25 20:40
2024-07-27 20:40
2024-08-05 20:40
2024-08-08 20:40
2024-08-10 20:40
2024-08-19 20:40
2024-08-22 20:40
2024-08-24 20:40
2024-09-02 20:40
2024-09-05 20:40
2024-09-07 20:40
2024-09-16 20:40
2024-09-19 20:40
2024-09-21 20:40
2024-09-30 20:40
2024-10-03 20:40
2024-10-05 20:40
2024-10-14 20:40
2024-10-17 20:40
2024-10-19 20:40
2024-10-28 20:40
2024-10-31 20:40
2024-11-02 20:40
2024-11-11 20:40
2024-11-14 20:40
2024-11-16 20:40
2024-11-25 20:40
2024-11-28 20:40
2024-11-30 20:40
2024-12-09 20:40
2024-12-12 20:40
2024-12-14 20:40
2024-12-23 20:40
2024-12-26 20:40
2024-12-28 20:40
2025-01-06 20:40
2025-01-09 20:40
2025-01-11 20:40
2025-01-20 20:40
2025-01-23 20:40
2025-01-25 20:40
2025-02-03 20:40
2025-02-06 20:40
2025-02-08 20:40
2025-02-17 20:40
2025-02-20 20:40
2025-02-22 20:40
2025-03-03 20:40
2025-03-06 20:40
2025-03-08 20:40
2025-03-17 20:40
2025-03-20 20:40
2025-03-22 20:40
2025-03-31 20:40
2025-04-03 20:40
2025-04-05 20:40
2025-04-14 20:40
2025-04-17 20:40
2025-04-19 20:40
2025-04-28 20:40
2025-05-01 20:40
2025-05-03 20:40
2025-05-12 20:40
2025-05-15 20:40
2025-05-17 20:40
2025-05-26 20:40
2025-05-29 20:40
2025-05-31 20:40
2025-06-09 20:40
2025-06-12 20:40
2025-06-14 20:40
2025-06-23 20:40
2025-06-26 20:40
2025-06-28 20:40
2025-07-07 20:40
2025-07-10 20:40
2025-07-12 20:40
2025-07-21 20:40
2025-07-24 20:40
2025-07-26 20:40
2025-08-04 20:40
2025-08-07 20:40
2025-08-09 20:40
2025-08-18 20:40
2025-08-21 20:40
2025-08-23 20:40
2025-09-01 20:40
2025-09-04 20:40
2025-09-06 20:40
2025-09-15 20:40
2025-09-18 20:40
2025-09-20 20:40
2025-09-29 20:40
2025-10-02 20:40
2025-10-04 20:40
2025-10-13 20:40
2025-10-16 20:40
2025-10-18 20:40
2025-10-27 20:40
2025-10-30 20:40
2025-11-01 20:40
2025-11-10 20:40
2025-11-13 20:40
2025-11-15 20:40
2025-11-24 20:40
2025-11-27 20:40
2025-11-29 20:40
2025-12-08 20:40
2025-12-11 20:40
2025-12-13 20:40
2025-12-22 20:40
2025-12-25 20:40
2025-12-27 20:40
2026-01-05 20:40
2026-01-08 20:40
2026-01-10 20:40
2026-01-19 20:40
2026-01-22 20:40
2026-01-24 20:40
2026-02-02 20:40
2026-02-05 20:40
2026-02-07 20:40
2026-02-16 20:40
2026-02-19 20:40
2026-02-21 20:40
2026-03-02 20:40
2026-03-05 20:40
2026-03-07 20:40
2026-03-16 20:40
2026-03-19 20:40
2026-03-21 20:40
2026-03-30 20:40
2026-04-02 20:40
2026-04-04 20:40
2026-04-13 20:40
2026-04-16 20:40
2026-04-18 20:40
2026-04-27 20:40
2026-04-30 20:40
2026-05-02 20:40
2026-05-11 20:40
2026-05-14 20:40
2026-05-16 20:40
2026-05-25 20:40
2026-05-28 20:40
2026-05-30 20:40
2026-06-08 20:40
2026-06-11 20:40
2026-06-13 20:40
2026-06-22 20:40
2026-06-25 20:40
2026-06-27 20:40
2026-07-06 20:40
2026-07-09 20:40
2026-07-11 20:40
2026-07-20 20:40
2026-07-23 20:40
2026-07-25 20:40
2026-08-03 20:40
2026-08-06 20:40
2026-08-08 20:40
2026-08-17 20:40
2026-08-20 20:40
2026-08-22 20:40
2026-08-31 20:40
2026-09-03 20:40
2026-09-05 20:40
2026-09-14 20:40
2026-09-17 20:40
2026-09-19 20:40
2026-09-28 20:40
2026-10-01 20:40
2026-10-03 20:40
2026-10-12 20:40
2026-10-15 20:40
2026-10-17 20:40
2026-10-26 20:40
2026-10-29 20:40
2026-10-31 20:40
2026-11-09 20:40
2026-11-12 20:40
2026-11-14 20:40
2026-11-23 20:40
2026-11-26 20:40
2026-11-28 20:40
2026-12-07 20:40
2026-12-10 20:40
2026-12-12 20:40
2026-12-21 20:40
2026-12-24 20:40
2026-12-26 20:40
Process finished with exit code 0
最终代码:
import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author dume
* @ClassName CronUtils
* @description: TODO
* @date 2024年06月06日
* @version: 1.0
*/
public class CronUtils {
/**
*
* @param startTime 定时任务开始时间 yyyy-MM-dd
* @param endTime 定时任务结束时间 yyyy-MM-dd
* @param executeTime 执行时间 HH:mm
* @param weekList 周几执行列表 [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六]
* @param interval 隔几周执行一次
* @return
*/
public static List<String> getExecuteTimeList(String startTime, String endTime, String executeTime, List<Integer> weekList, int interval) {
List<String> list = new ArrayList<>();
try {
String startStr = startTime + executeTime;
String endStr = endTime + executeTime;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm");
Date endDate = dateFormat.parse(endStr);
Date startDate = dateFormat.parse(startStr);
Date now = new Date();
//设置日期过期,返回空
if (now.getTime() > endDate.getTime()) {
return new ArrayList<>();
}
interval++;
for (Integer week : weekList) {
String cronExpression = createCronStr(executeTime, week);
if (StringUtils.isBlank(cronExpression)) {
continue;
}
Date startTime2 = getMonday(startDate);
Date nextExecutionTime = getNextExecutionTime(cronExpression,startTime2);
int add = 0;
Date nownext = nextExecutionTime;
while (nownext.getTime() <= endDate.getTime()) {
nownext = new Date(nextExecutionTime.getTime() + add * interval * 7 * 24 * 60 * 60 * 1000L);
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String str = dateFormat2.format(nownext);
if (nownext.getTime() <= endDate.getTime() && nownext.getTime()>=startDate.getTime()) {
list.add(str);
}
add++;
}
}
Collections.sort(list);
} catch (ParseException e) {
System.out.println("解析异常: " + e.getMessage());
e.printStackTrace();
}
return list;
}
/**
*计算cron表达式
*@param executeTime 执行时间 HH:mm
* @param week 周几
* @return cron表达式
* @throws ParseException
*/
public static String createCronStr(String executeTime, Integer week) {
String weekStr = String.valueOf(week + 1);
// 设置cron表达式,周三,下午3点30分执行
String cronExpression = "0 %1$s %2$s ? * %3$s";
String[] times = executeTime.split(":");
String hour = times[0];
String minute = times[1];
return String.format(cronExpression, minute, hour, weekStr);
}
/**
* 计算下次执行时间
* @param cronExpression cron
* @param startTime2 开始时间(开始时间的周一时间)
* @return
* @throws ParseException
*/
public static Date getNextExecutionTime(String cronExpression, Date startTime2) throws ParseException {
CronExpression cron = new CronExpression(cronExpression);
Date nextExecutionTime = cron.getNextValidTimeAfter(startTime2);
System.out.println("下次执行时间: " + nextExecutionTime);
return nextExecutionTime;
}
/**
* 开始时间点的周一时间
* @param startDate
* @return
*/
public static Date getMonday(Date startDate){
/**
* 计算给出时间的周一时间
*/
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
// 将小时、分钟、秒和毫秒字段设置为0
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// 将日期设置为本周第一天(默认为周日)的前一天(即周一)
calendar.add(Calendar.DAY_OF_WEEK, Calendar.MONDAY - calendar.get(Calendar.DAY_OF_WEEK));
// 输出周一0点的时间
return calendar.getTime();
}
public static void main(String[] args) {
List<Integer> week = new ArrayList<>();
week.add(1);
week.add(4);
week.add(6);
long start = System.currentTimeMillis();
List<String> list = getExecuteTimeList("2024-06-15", "2026-12-31", "20:40", week, 1);
long end = System.currentTimeMillis();
System.out.println(end - start + " ms");
for(String element : list) {
System.out.println(element);
}
}
}