schedule.java
来自「数据仓库展示程序」· Java 代码 · 共 834 行 · 第 1/3 页
JAVA
834 行
* Returns the next occurrence of this schedule after a given date. If
* <code>after</code> is null, returns the first occurrence. If there are
* no further occurrences, returns null.
*
* @param after if not null, returns the first occurrence after this
* point in time; if null, returns the first occurrence ever.
* @param strict If <code>after</code> is an occurrence,
* <code>strict</code> determines whether this method returns it, or
* the next occurrence. If <code>strict</code> is true, the value
* returned is strictly greater than <code>after</code>.
*/
public Date nextOccurrence(Date after, boolean strict) {
if (after == null ||
begin != null && begin.after(after)) {
after = begin;
strict = false;
}
if (after == null) {
after = new Date(0);
}
Date next = nextOccurrence0(after, strict);
// if there is an upper bound, and this is not STRICTLY before it,
// there's no next occurrence
if (next != null &&
end != null &&
!next.before(end)) {
next = null;
}
return next;
}
private Date nextOccurrence0(Date after, boolean strict) {
Calendar next = ScheduleUtil.createCalendar(after);
if (tz == null || tz.getID().equals("GMT")) {
return nextOccurrence1(next, strict);
} else {
int offset;
if (next == null) {
offset = tz.getRawOffset();
} else {
offset = ScheduleUtil.timezoneOffset(tz, next);
}
// Add the offset to the calendar, so that the calendar looks like
// the local time (even though it is still in GMT). Suppose an
// event runs at 12:00 JST each day. At 02:00 GMT they ask for the
// next event. We convert this to local time, 11:00 JST, by adding
// the 9 hour offset. We will convert the result back to GMT by
// subtracting the offset.
next.add(Calendar.MILLISECOND, offset);
Date result = nextOccurrence1(next, strict);
if (result == null) {
return null;
}
Calendar resultCalendar = ScheduleUtil.createCalendar(result);
int offset2 = ScheduleUtil.timezoneOffset(tz, resultCalendar);
// Shift the result back again.
resultCalendar.add(Calendar.MILLISECOND, -offset2);
return resultCalendar.getTime();
}
}
private Date nextOccurrence1(Calendar earliest, boolean strict) {
Calendar earliestDay = ScheduleUtil.floor(earliest);
Calendar earliestTime = ScheduleUtil.getTime(earliest);
// first, try a later time on the same day
Calendar nextDay = dateSchedule.nextOccurrence(earliestDay, false);
Calendar nextTime = timeSchedule.nextOccurrence(earliestTime, strict);
if (nextTime == null) {
// next, try the first time on a later day
nextDay = dateSchedule.nextOccurrence(earliestDay, true);
nextTime = timeSchedule.nextOccurrence(ScheduleUtil.midnightTime, false);
}
if (nextDay == null || nextTime == null) {
return null;
}
nextDay.set(Calendar.HOUR_OF_DAY, nextTime.get(Calendar.HOUR_OF_DAY));
nextDay.set(Calendar.MINUTE, nextTime.get(Calendar.MINUTE));
nextDay.set(Calendar.SECOND, nextTime.get(Calendar.SECOND));
nextDay.set(Calendar.MILLISECOND, nextTime.get(Calendar.MILLISECOND));
return nextDay.getTime();
}
}
/**
* A <code>TimeSchedule</code> generates a series of times within a day.
*/
interface TimeSchedule {
/**
* Returns the next occurrence at or after <code>after</code>. If
* <code>after</code> is null, returns the first occurrence. If there are
* no further occurrences, returns null.
*
* @param strict if true, return time must be after <code>after</code>, not
* equal to it
*/
Calendar nextOccurrence(Calendar earliest, boolean strict);
}
/**
* A <code>OnceTimeSchedule</code> fires at one and only one time.
*/
class OnceTimeSchedule implements TimeSchedule {
Calendar time;
OnceTimeSchedule(Calendar time) {
ScheduleUtil.assertTrue(time != null);
ScheduleUtil.assertTrue(ScheduleUtil.isTime(time));
this.time = time;
}
public Calendar nextOccurrence(Calendar after, boolean strict) {
if (after == null) {
return time;
}
if (time.after(after)) {
return time;
}
if (!strict && time.equals(after)) {
return time;
}
return null;
}
}
/**
* A <code>DateSchedule</code> returns a series of dates.
*/
interface DateSchedule {
/**
* Returns the next date when this schedule fires.
*
* @pre earliest != null
*/
Calendar nextOccurrence(Calendar earliest, boolean strict);
};
/**
* A <code>DailyDateSchedule</code> fires every day.
*/
class DailyDateSchedule implements DateSchedule {
int period;
int beginOrdinal;
DailyDateSchedule(Calendar begin, int period) {
this.period = period;
ScheduleUtil.assertTrue(period > 0, "period must be positive");
this.beginOrdinal = ScheduleUtil.julianDay(
begin == null ? ScheduleUtil.epochDay : begin);
}
public Calendar nextOccurrence(Calendar day, boolean strict) {
day = (Calendar) day.clone();
if (strict) {
day.add(Calendar.DATE, 1);
}
while (true) {
int ordinal = ScheduleUtil.julianDay(day);
if ((ordinal - beginOrdinal) % period == 0) {
return day;
}
day.add(Calendar.DATE, 1);
}
}
}
/**
* A <code>WeeklyDateSchedule</code> fires every week. A bitmap indicates
* which days of the week it fires.
*/
class WeeklyDateSchedule implements DateSchedule {
int period;
int beginOrdinal;
int daysOfWeekBitmap;
WeeklyDateSchedule(Calendar begin, int period, int daysOfWeekBitmap) {
this.period = period;
ScheduleUtil.assertTrue(period > 0, "period must be positive");
this.beginOrdinal = ScheduleUtil.julianDay(
begin == null ? ScheduleUtil.epochDay : begin) / 7;
this.daysOfWeekBitmap = daysOfWeekBitmap;
ScheduleUtil.assertTrue(
(daysOfWeekBitmap & Schedule.allDaysOfWeekBitmap) != 0,
"weekly schedule must have at least one day set");
ScheduleUtil.assertTrue(
(daysOfWeekBitmap & Schedule.allDaysOfWeekBitmap) == daysOfWeekBitmap,
"weekly schedule has bad bits set: " + daysOfWeekBitmap);
}
public Calendar nextOccurrence(Calendar earliest, boolean strict) {
earliest = (Calendar) earliest.clone();
if (strict) {
earliest.add(Calendar.DATE, 1);
}
int i = 7 + period; // should be enough
while (i-- > 0) {
int dayOfWeek = earliest.get(Calendar.DAY_OF_WEEK);
if ((daysOfWeekBitmap & (1 << dayOfWeek)) != 0) {
int ordinal = ScheduleUtil.julianDay(earliest) / 7;
if ((ordinal - beginOrdinal) % period == 0) {
return earliest;
}
}
earliest.add(Calendar.DATE, 1);
}
throw ScheduleUtil.newInternal(
"weekly date schedule is looping -- maybe the " +
"bitmap is empty: " + daysOfWeekBitmap);
}
}
/**
* A <code>MonthlyByDayDateSchedule</code> fires on a particular set of days
* every month.
*/
class MonthlyByDayDateSchedule implements DateSchedule {
int period;
int beginMonth;
int daysOfMonthBitmap;
MonthlyByDayDateSchedule(
Calendar begin, int period, int daysOfMonthBitmap) {
this.period = period;
ScheduleUtil.assertTrue(period > 0, "period must be positive");
this.beginMonth = begin == null ? 0 : monthOrdinal(begin);
this.daysOfMonthBitmap = daysOfMonthBitmap;
ScheduleUtil.assertTrue(
(daysOfMonthBitmap & Schedule.allDaysOfMonthBitmap) != 0,
"monthly day schedule must have at least one day set");
ScheduleUtil.assertTrue(
(daysOfMonthBitmap & Schedule.allDaysOfMonthBitmap) ==
daysOfMonthBitmap,
"monthly schedule has bad bits set: " + daysOfMonthBitmap);
}
public Calendar nextOccurrence(Calendar earliest, boolean strict) {
earliest = (Calendar) earliest.clone();
if (strict) {
earliest.add(Calendar.DATE, 1);
}
int i = 31 + period; // should be enough
while (i-- > 0) {
int month = monthOrdinal(earliest);
if ((month - beginMonth) % period != 0) {
// not this month! move to first of next month
earliest.set(Calendar.DAY_OF_MONTH, 1);
earliest.add(Calendar.MONTH, 1);
continue;
}
int dayOfMonth = earliest.get(Calendar.DAY_OF_MONTH);
if ((daysOfMonthBitmap & (1 << dayOfMonth)) != 0) {
return earliest;
}
earliest.add(Calendar.DATE, 1);
if ((daysOfMonthBitmap & (1 << Schedule.LAST_DAY_OF_MONTH)) != 0 &&
earliest.get(Calendar.DAY_OF_MONTH) == 1) {
// They want us to fire on the last day of the month, and
// now we're at the first day of the month, so we must have
// been at the last. Backtrack and return it.
earliest.add(Calendar.DATE, -1);
return earliest;
}
}
throw ScheduleUtil.newInternal(
"monthly-by-day date schedule is looping -- maybe " +
"the bitmap is empty: " + daysOfMonthBitmap);
}
private static int monthOrdinal(Calendar earliest) {
return earliest.get(Calendar.YEAR) * 12 +
earliest.get(Calendar.MONTH);
}
}
/**
* A <code>MonthlyByWeekDateSchedule</code> fires on particular days of
* particular weeks of a month.
*/
class MonthlyByWeekDateSchedule implements DateSchedule {
int period;
int beginMonth;
int daysOfWeekBitmap;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?