import java.util.Calendar;
import java.util.Date;
/**
* 周期<br>
* 实现了每天,每周,每月,每年的间隔一定时间重复执行的周期<br>
* <pre>
* // 每天2点执行1次
* Period.getDailyOncePeriod(2*60*60*1000);
* // 每周3的5点执行1次
* Period.getWeeklyOncePeriod((3*24+5)*60*60*1000);
* // 每天隔2小时1次
* Period.getDailyPeriod(2*60*60*1000);
* // 每天3点-8点隔1小时1次(6表示每天仅执行6次, 6=8-3+1)
* Period.getDailyPeriod(1*60*60*1000, 3*60*60*1000, 6);
* </pre>
* 输入参数计算单位的自动转换<br>
* <pre>
* // 每天2点执行1次(Period.HOUR=以小时为时间单位)
* Period.HOUR.getDailyOncePeriod(2);
* // 每天隔半小时1次(Period.MINUTE=以分钟为时间单位)
* Period.MINUTE.getDailyPeriod(30);
* </pre>
* @author zhaohuihua
*/
public class Period {
/** 一天的毫秒数 **/
private static final long ONEDAY = 24 * 60 * 60 * 1000L;
/** 每天的周期 **/
public static final int DAILY = 0;
/** 每周的周期 **/
public static final int WEEKLY = 1;
/** 每月的周期 **/
public static final int MONTHLY = 2;
/** 每年的周期 **/
public static final int YEARLY = 3;
/** 以天计算的时间单位, 该单位的所有方法的时间参数都以天表示 **/
public static final Unit DAY = new Unit(ONEDAY);
/** 以小时计算的时间单位, 该单位的所有方法的时间参数都以小时表示 **/
public static final Unit HOUR = new Unit(60 * 60 * 1000L);
/** 以分计算的时间单位, 该单位的所有方法的时间参数都以分表示 **/
public static final Unit MINUTE = new Unit(60 * 1000L);
/** 以秒计算的时间单位, 该单位的所有方法的时间参数都以秒表示 **/
public static final Unit SECOND = new Unit(1000L);
/** 以毫秒计算的时间单位, 该单位的所有方法的时间参数都以毫秒表示 **/
public static final Unit MILLISECOND = new Unit(1L);
/** 类型(0.DAILY|1.WEEKLY|2.MONTHLY|3.YEARLY) **/
private final int type;
/** 间隔时间 **/
private final long interval;
/** 偏移时间(从每个周期的什么时间开始) **/
private final long offset;
/** 执行次数(每个周期的最大执行次数), 0表示无限制 **/
private final int times;
/**
* 计算时的参照时间点<br>
* 如果为null, 每次计算时读取系统时间, 并计算其下一时间点<br>
* 如果指定了时间, 则计算该固定时间点的下一时间点
*/
private Date date;
/** 是否输出日志(用于测试) **/
private static boolean log = false;
/**
* 私有全参数构造函数
* @param type 类型(DAILY | WEEKLY | MONTHLY | YEARLY)
* @param interval 间隔时间
* @param offset 偏移时间(从每个周期的什么时间开始)
* @param times 执行次数(每个周期的最大执行次数), 0表示无限制
* @param date 计算时的参照时间点<br>
* 如果为null, 每次计算时读取系统时间, 并计算其下一时间点<br>
* 如果指定了时间, 则计算该固定时间点的下一时间点
*/
private Period(int type, long interval, long offset, int times, Date date) {
// 参数检查
if(type != 0 && type != 1 && type != 2 && type != 3)
throw new IllegalArgumentException("type");
if(interval < 0)
throw new IllegalArgumentException("interval");
if(offset < 0)
throw new IllegalArgumentException("offset");
if(times < 0)
throw new IllegalArgumentException("times");
// 赋值
this.type = type;
this.interval = interval;
this.offset = offset;
this.times = times;
this.date = date;
}
/** 类型(0.DAILY|1.WEEKLY|2.MONTHLY|3.YEARLY) **/
public int getType() {
return type;
}
/** 间隔时间 **/
public long getInterval() {
return interval;
}
/** 偏移时间(从每个周期的什么时间开始) **/
public long getOffset() {
return offset;
}
/** 执行次数(每个周期的最大执行次数), 0表示无限制 **/
public int getTimes() {
return times;
}
/**
* 计算时的参照时间点<br>
* 如果为null, 每次计算时读取系统时间, 并计算其下一时间点<br>
* 如果指定了时间, 则计算该固定时间点的下一时间点
*/
public Date getPoint() {
return date;
}
/**
* 移至某个计算所依据的时间点
* @param date 时间点
* @return
*/
public Period toPoint(Date date) {
return new Period(type, interval, offset, times, date);
}
/**
* 移至下个间隔时间点, 并将该点作为计算所依据的时间点
* @return
*/
public Period toNextTime() {
return new Period(type, interval, offset, times, getNextTime());
}
/**
* 获取周期的下一时间点
* @return
*/
public Date getNextTime() {
Date date = this.date != null ? this.date : new Date();
return new Date(date.getTime() + getNextTimeOffset(date));
}
/**
* 获取到周期的下一时间点的毫秒数
* @return
*/
public long getNextTimeOffset() {
return getNextTimeOffset(date != null ? date : new Date());
}
/**
* 获取到周期的下一时间点的毫秒数
* @param date 参照时间点
* @return
*/
private long getNextTimeOffset(final Date date) {
log("------------------------------");
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
long result = 0L;
// 当前毫秒数
long current = calendar.getTimeInMillis();
log("当前时间: " + DateTools.dateToString(date));
// 本周期的开始时间的毫秒数
long period = getFirstTimeInPeriod(date);
log("本周期起点: " + DateTools.dateToString(new Date(period)));
// 起点, 本周期第一个时间点
long starting = period + offset;
log("第一个时间点: " + DateTools.dateToString(new Date(starting)));
if(current < starting) { // 小于起点
// 距起点的毫秒数
result = starting - current;
} else if(interval == 0L) {
result = 0L;
} else {
// 本周期已经过了的毫秒数, 相对于起点
long elapse = current - starting;
log("已消逝时间: " + DateTools.formatInterval(elapse));
// 本周期已经过了几个时间间隔
long count = elapse / interval + 1;
log("已消逝次数: " + count);
for(long i = 0; i < count && log; i++) {
if(i == 5 && count > 12) {
log("...");
i = count - 5;
}
long temp = starting + i * interval;
log((i + 1) + ". " + DateTools.dateToString(new Date(temp)));
}
// 下一时间点的毫秒数
long nextTime = starting + count * interval;
log("下一时间点: " + DateTools.dateToString(new Date(nextTime)));
// 下一周期的开始时间的毫秒数
long nextPeriod = getFirstTimeInPeriod(date, 1);
log("下一周期: " + DateTools.dateToString(new Date(nextPeriod)));
// 下一时间点在本周期内, 并且, 未超出本周期的次数限制
if(nextTime < nextPeriod && (times == 0 || count < times)) {
// 距下一时间点的毫秒数
result = nextTime - current;
} else {
// 距下一周期第一个时间点的毫秒数
result = nextPeriod + offset - current;
}
}
log("结果: " + DateTools.dateToString(new Date(current + result)));
return result;
}
/**
* 获取参照时间点所在的周期的开始时间点
* @param date 参照时间点
* @return
*/
private long getFirstTimeInPeriod(final Date date) {
return getFirstTimeInPeriod(date, 0);
}
/**
* 获取参照时间点所在的周期的开始时间点
* @param date 参照时间点
* @param periodOffset 偏移几个周期<br>
* 如0表示当前周期, 1表示下一周期, -1表示上一周期, 类推
* @return
*/
private long getFirstTimeInPeriod(final Date date, int periodOffset) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
switch(type) {
case DAILY:
if(periodOffset != 0) { // 周期偏移
periodOffset += calendar.get(Calendar.DAY_OF_MONTH);
calendar.set(Calendar.DAY_OF_MONTH, periodOffset);
}
break;
case WEEKLY:
if(periodOffset != 0) { // 周期偏移
periodOffset += calendar.get(Calendar.WEEK_OF_YEAR);
calendar.set(Calendar.WEEK_OF_YEAR, periodOffset);
}
// 日期置于周期起始位置
calendar.set(Calendar.DAY_OF_WEEK, 1);
break;
case MONTHLY:
if(periodOffset != 0) { // 周期偏移
periodOffset += calendar.get(Calendar.MONTH);
calendar.set(Calendar.MONTH, periodOffset);
}
// 日期置于周期起始位置
calendar.set(Calendar.DAY_OF_MONTH, 1);
break;
case YEARLY:
if(periodOffset != 0) { // 周期偏移
periodOffset += calendar.get(Calendar.YEAR);
calendar.set(Calendar.YEAR, periodOffset);
}
// 日期置于周期起始位置
calendar.set(Calendar.DAY_OF_YEAR, 1);
break;
}
// 时分秒置零
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis();
}
private void log(String msg) {
if(log) System.out.println(msg);
}
/**
* 每天执行一次的周期(时间单位为毫秒)
* @param offset 偏移时间(每天的什么时间执行)
* @return
*/
public static Period getDailyOncePeriod(long offset) {
return MILLISECOND.getDailyOncePeriod(offset);
}
/**
* 每周执行一次的周期(时间单位为毫秒)
* @param offset 偏移时间(每周的什么时间执行)
* @return
*/
public static Period getWeeklyOncePeriod(long offset) {
return MILLISECOND.getWeeklyOncePeriod(offset);
}
/**
* 每月执行一次的周期(时间单位为毫秒)
* @param offset 偏移时间(每月的什么时间执行)
* @return
*/
public static Period getMonthlyOncePeriod(long offset) {
return MILLISECOND.getMonthlyOncePeriod(offset);
}
/**
* 每年执行一次的周期(时间单位为毫秒)
* @param offset 偏移时间(每年的什么时间执行)
* @return
*/
public static Period getYearlyOncePeriod(long offset) {
return MILLISECOND.getYearlyOncePeriod(offset);
}
/**
* 每天的周期(时间单位为毫秒)
* @param interval 间隔时间
* @return
*/
public static Period getDailyPeriod(long interval) {
return MILLISECOND.getDailyPeriod(interval);
}
/**
* 每天的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每天的什么时间执行)
* @return
*/
public static Period getDailyPeriod(long interval, long offset) {
return MILLISECOND.getDailyPeriod(interval, offset);
}
/**
* 每天的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每天的什么时间执行)
* @param times 执行次数(每天的最大执行次数), 0表示无限制
* @return
*/
public static Period getDailyPeriod(long interval, long offset,
int times) {
return MILLISECOND.getDailyPeriod(interval, offset, times);
}
/**
* 每周的周期(时间单位为毫秒)
* @param interval 间隔时间
* @return
*/
public static Period getWeeklyPeriod(long interval) {
return MILLISECOND.getWeeklyPeriod(interval);
}
/**
* 每周的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每周的什么时间执行)
* @return
*/
public static Period getWeeklyPeriod(long interval, long offset) {
return MILLISECOND.getWeeklyPeriod(interval, offset);
}
/**
* 每周的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每周的什么时间执行)
* @param times 执行次数(每周的最大执行次数), 0表示无限制
* @return
*/
public static Period getWeeklyPeriod(long interval, long offset,
int times) {
return MILLISECOND.getWeeklyPeriod(interval, offset, times);
}
/**
* 每月的周期(时间单位为毫秒)
* @param interval 间隔时间
* @return
*/
public static Period getMonthlyPeriod(long interval) {
return MILLISECOND.getMonthlyPeriod(interval);
}
/**
* 每月的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每月的什么时间执行)
* @return
*/
public static Period getMonthlyPeriod(long interval, long offset) {
return MILLISECOND.getMonthlyPeriod(interval, offset);
}
/**
* 每月的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每月的什么时间执行)
* @param times 执行次数(每月的最大执行次数), 0表示无限制
* @return
*/
public static Period getMonthlyPeriod(long interval, long offset,
int times) {
return MILLISECOND.getMonthlyPeriod(interval, offset, times);
}
/**
* 每年的周期(时间单位为毫秒)
* @param interval 间隔时间
* @return
*/
public static Period getYearlyPeriod(long interval) {
return MILLISECOND.getYearlyPeriod(interval);
}
/**
* 每年的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每年的什么时间执行)
* @return
*/
public static Period getYearlyPeriod(long interval, long offset) {
return MILLISECOND.getYearlyPeriod(interval, offset);
}
/**
* 每年的周期(时间单位为毫秒)
* @param interval 间隔时间
* @param offset 偏移时间(每年的什么时间执行)
* @param times 执行次数(每年的最大执行次数), 0表示无限制
* @return
*/
public static Period getYearlyPeriod(long interval, long offset,
int times) {
return MILLISECOND.getYearlyPeriod(interval, offset, times);
}
/**
* 时间单位<br>
* 如: Period.HOUR = 以小时作为时间单位<br>
* 该单位的所有方法的时间参数都以小时表示<br>
* Period.HOUR.getDailyPeriod(2); 表示每天隔2小时执行一次的周期<br>
* 已定义的时间单位有:<br>
* Period.DAY = 以天作为时间单位<br>
* Period.HOUR = 以小时作为时间单位<br>
* Period.MINUTE = 以分作为时间单位<br>
* Period.SECOND = 以秒作为时间单位<br>
* Period.MILLISECOND = 以毫秒作为时间单位<br>
*/
public static class Unit {
/** 时间单位转换为毫秒的比率**/
private long rate;
/**
* 时间单位
* @param rate 时间单位转换为毫秒的比率
*/
private Unit(long rate) {
this.rate = rate;
}
/**
* 每天执行一次的周期
* @param offset 偏移时间(每天的什么时间执行)
* @return
*/
public Period getDailyOncePeriod(long offset) {
return new Period(DAILY, ONEDAY, offset * rate, 1, null);
}
/**
* 每周执行一次的周期
* @param offset 偏移时间(每周的什么时间执行)
* @return
*/
public Period getWeeklyOncePeriod(long offset) {
return new Period(WEEKLY, 7 * ONEDAY, offset * rate, 1, null);
}
/**
* 每月执行一次的周期
* @param offset 偏移时间(每月的什么时间执行)
* @return
*/
public Period getMonthlyOncePeriod(long offset) {
return new Period(MONTHLY, 28 * ONEDAY, offset * rate, 1, null);
}
/**
* 每年执行一次的周期
* @param offset 偏移时间(每年的什么时间执行)
* @return
*/
public Period getYearlyOncePeriod(long offset) {
return new Period(YEARLY, 365 * ONEDAY, offset * rate, 1, null);
}
/**
* 每天的周期
* @param interval 间隔时间
* @return
*/
public Period getDailyPeriod(long interval) {
return new Period(DAILY, interval * rate, 0, 0, null);
}
/**
* 每天的周期
* @param interval 间隔时间
* @param offset 偏移时间(每天的什么时间执行)
* @return
*/
public Period getDailyPeriod(long interval, long offset) {
return new Period(DAILY, interval * rate, offset * rate, 0, null);
}
/**
* 每天的周期
* @param interval 间隔时间
* @param offset 偏移时间(每天的什么时间执行)
* @param times 执行次数(每天的最大执行次数), 0表示无限制
* @return
*/
public Period getDailyPeriod(long interval, long offset, int times) {
return new Period(DAILY, interval*rate, offset*rate, times, null);
}
/**
* 每周的周期
* @param interval 间隔时间
* @return
*/
public Period getWeeklyPeriod(long interval) {
return new Period(WEEKLY, interval * rate, 0, 0, null);
}
/**
* 每周的周期
* @param interval 间隔时间
* @param offset 偏移时间(每周的什么时间执行)
* @return
*/
public Period getWeeklyPeriod(long interval, long offset) {
return new Period(WEEKLY, interval * rate, offset * rate, 0, null);
}
/**
* 每周的周期
* @param interval 间隔时间
* @param offset 偏移时间(每周的什么时间执行)
* @param times 执行次数(每周的最大执行次数), 0表示无限制
* @return
*/
public Period getWeeklyPeriod(long interval, long offset, int times) {
return new Period(WEEKLY, interval*rate, offset*rate, times, null);
}
/**
* 每月的周期
* @param interval 间隔时间
* @return
*/
public Period getMonthlyPeriod(long interval) {
return new Period(MONTHLY, interval * rate, 0, 0, null);
}
/**
* 每月的周期
* @param interval 间隔时间
* @param offset 偏移时间(每月的什么时间执行)
* @return
*/
public Period getMonthlyPeriod(long interval, long offset) {
return new Period(MONTHLY, interval * rate, offset * rate, 0, null);
}
/**
* 每月的周期
* @param interval 间隔时间
* @param offset 偏移时间(每月的什么时间执行)
* @param times 执行次数(每月的最大执行次数), 0表示无限制
* @return
*/
public Period getMonthlyPeriod(long interval, long offset, int times) {
return new Period(MONTHLY, interval*rate, offset*rate, times, null);
}
/**
* 每年的周期
* @param interval 间隔时间
* @return
*/
public Period getYearlyPeriod(long interval) {
return new Period(YEARLY, interval * rate, 0, 0, null);
}
/**
* 每年的周期
* @param interval 间隔时间
* @param offset 偏移时间(每年的什么时间执行)
* @return
*/
public Period getYearlyPeriod(long interval, long offset) {
return new Period(YEARLY, interval * rate, offset * rate, 0, null);
}
/**
* 每年的周期
* @param interval 间隔时间
* @param offset 偏移时间(每年的什么时间执行)
* @param times 执行次数(每年的最大执行次数), 0表示无限制
* @return
*/
public Period getYearlyPeriod(long interval, long offset, int times) {
return new Period(YEARLY, interval*rate, offset*rate, times, null);
}
}
/** 测试 **/
public static void main(String[] args) {
Period.log = true;
System.out.println("每天, 间隔1小时30分钟, 2小时后开始, 次数无限制");
Period.MINUTE.getDailyPeriod(90, 2*60, 0)
.toPoint(DateTools.parseDate("2009-02-05 03:10:10.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每天, 间隔1小时30分钟, 2小时后开始, 次数2");
Period.MINUTE.getDailyPeriod(90, 2*60, 2)
.toPoint(DateTools.parseDate("2009-02-05 03:10:10.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每周, 间隔15小时, 26小时后开始, 次数无限制");
Period.HOUR.getWeeklyPeriod(15, 26, 0)
.toPoint(DateTools.parseDate("2009-02-07 22:00:00.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每周, 间隔15小时, 26小时后开始, 次数无限制");
Period.HOUR.getWeeklyPeriod(15, 26, 0)
.toPoint(DateTools.parseDate("2009-02-05 10:10:10.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每月, 间隔15小时, 26小时后开始, 次数无限制");
Period.HOUR.getMonthlyPeriod(15, 26, 0)
.toPoint(DateTools.parseDate("2009-02-28 23:00:00.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每天5点执行一次");
Period.HOUR.getDailyOncePeriod(5)
.toPoint(DateTools.parseDate("2009-02-05 10:10:10.000"))
.toNextTime().toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每隔5小时执行一次");
Period.HOUR.getYearlyPeriod(5)
.toPoint(DateTools.parseDate("2009-02-05 18:10:10.000"))
.toNextTime().toNextTime();
System.out.println(); System.out.println();
System.out.println("每周3的5点执行一次");
Period.HOUR.getWeeklyOncePeriod(3*24+5)
.toPoint(DateTools.parseDate("2009-02-05 10:10:10.000"))
.toNextTime().toNextTime().toNextTime();
Period.log = false;
}
}
周期(实现了每天,每周,每月,每年的间隔一定时间重复执行的周期)
最新推荐文章于 2023-08-29 17:37:28 发布