package org.agnitas.util;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class DateUtilities {
public static final SimpleDateFormat DD_MM_YYYY_HH_MM_SS = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
public static final SimpleDateFormat DD_MM_YYYY_HH = new SimpleDateFormat("dd.MM.yyyy HH");
public static final SimpleDateFormat DD_MM_YYYY = new SimpleDateFormat("dd.MM.yyyy");
public static final SimpleDateFormat YYYY_MM_DD_HH_MM_SS_MS = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss,SSS");
public static final SimpleDateFormat YYYY_MM_DD_HH_MM_SS_FORFILENAMES = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
public static final SimpleDateFormat YYYYMMDD = new java.text.SimpleDateFormat("yyyyMMdd");
public enum TimespanID {
previous_week,
previous_7_days,
previous_month,
current_year,
previous_year;
public static TimespanID fromString(String value) {
if (value != null) {
for (TimespanID item : TimespanID.values()) {
if (item.toString().replace("_", "").equalsIgnoreCase(value.replace("_", ""))) {
return item;
}
}
}
throw new IllegalArgumentException("Invalid TimespanID");
}
}
public static Tuple<Date, Date> getTimespan(String timespanId) {
return getTimespan(TimespanID.fromString(timespanId));
}
public static Tuple<Date, Date> getTimespan(TimespanID timespanId) {
return getTimespan(timespanId, null);
}
public static Tuple<Date, Date> getTimespan(TimespanID timespanId, Date calculationBase) {
Date now = calculationBase;
if (now == null) {
now = new Date();
}
Calendar today = new GregorianCalendar();
today.setTime(now);
today = removeTime(today);
Date start;
Date end;
if (TimespanID.previous_week == timespanId) {
Calendar previousWeekStart = (GregorianCalendar) today.clone();
previousWeekStart.add(Calendar.DAY_OF_MONTH, -7);
previousWeekStart.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
start = previousWeekStart.getTime();
Calendar previousWeekEnd = (GregorianCalendar) today.clone();
previousWeekEnd.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
previousWeekEnd.add(Calendar.MILLISECOND, -1);
end = previousWeekEnd.getTime();
} else if (TimespanID.previous_7_days == timespanId) {
Calendar sevenDaysAgo = (GregorianCalendar) today.clone();
sevenDaysAgo.add(Calendar.DAY_OF_MONTH, -7);
start = sevenDaysAgo.getTime();
Calendar yesterdayEnd = (GregorianCalendar) today.clone();
yesterdayEnd.add(Calendar.MILLISECOND, -1);
end = yesterdayEnd.getTime();
} else if (TimespanID.previous_month == timespanId) {
Calendar oneMonthAgo = (GregorianCalendar) today.clone();
oneMonthAgo.set(Calendar.DAY_OF_MONTH, 1);
oneMonthAgo.add(Calendar.MONTH, -1);
start = oneMonthAgo.getTime();
Calendar monthEnd = (GregorianCalendar) today.clone();
monthEnd.set(Calendar.DAY_OF_MONTH, 1);
monthEnd.add(Calendar.MILLISECOND, -1);
end = monthEnd.getTime();
} else if (TimespanID.current_year == timespanId) {
Calendar yearStart = (GregorianCalendar) today.clone();
yearStart.set(Calendar.DAY_OF_MONTH, 1);
yearStart.set(Calendar.MONTH, Calendar.JANUARY);
start = yearStart.getTime();
Calendar oneMillisecondAgo = (GregorianCalendar) today.clone();
oneMillisecondAgo.add(Calendar.MILLISECOND, -1);
end = oneMillisecondAgo.getTime();
} else if (TimespanID.previous_year == timespanId) {
Calendar previousYearStart = (GregorianCalendar) today.clone();
previousYearStart.set(Calendar.DAY_OF_MONTH, 1);
previousYearStart.set(Calendar.MONTH, Calendar.JANUARY);
previousYearStart.add(Calendar.YEAR, -1);
start = previousYearStart.getTime();
Calendar previousYearEnd = (GregorianCalendar) today.clone();
previousYearEnd.set(Calendar.DAY_OF_MONTH, 1);
previousYearEnd.set(Calendar.MONTH, Calendar.JANUARY);
previousYearEnd.add(Calendar.MILLISECOND, -1);
end = previousYearEnd.getTime();
} else {
throw new IllegalArgumentException("TimespanID is invalid");
}
return new Tuple<Date, Date>(start, end);
}
public static Calendar getTodayWithoutTime() {
return removeTime(new GregorianCalendar());
}
public static Calendar removeTime(Calendar calendar) {
Calendar returnCalendar = (Calendar) calendar.clone();
returnCalendar.set(Calendar.HOUR_OF_DAY, 0);
returnCalendar.set(Calendar.MINUTE, 0);
returnCalendar.set(Calendar.SECOND, 0);
returnCalendar.set(Calendar.MILLISECOND, 0);
return returnCalendar;
}
/**
* Calculation of next scheduled job start
* Timingparameter may contain weekdays, clocktimes, months, quarters and holidays
*
* Allowed parameters:
* "ONCE" => only once (returns null)
* "0600;0800" => daily at 06:00 and 08:00
* "MoMi:1700" => Every monday and wednesday at 17:00
* "M05:1600" => every 05th day of month at 16:00
* "Q:1600" => every first day of quarter at 16:00
* "QW:1600" => every first working day of quarter at 16:00
* "MoDiMiDoFr:1700;!23012011" => mondyas to fridays at 17:00 exept for 23.01.2011 (Holidays marked by '!')
*
* All values may be combined separated by semicolons.
*
* @param timingString
* @return
* @throws Exception
*/
public static Date calculateNextJobStart(String timingString) {
GregorianCalendar now = new GregorianCalendar();
GregorianCalendar returnStart = new GregorianCalendar();
returnStart.add(GregorianCalendar.YEAR, 1);
// Holidays to exclude
List<GregorianCalendar> excludedDays = new ArrayList<GregorianCalendar>();
if (timingString.equalsIgnoreCase("once"))
return null;
String[] timingParameterList = timingString.split(";");
for (String timingParameter : timingParameterList) {
if (timingParameter.startsWith("!")) {
try {
GregorianCalendar exclusionDate = new GregorianCalendar();
exclusionDate.setTime(new SimpleDateFormat("ddMMyyyy").parse(timingParameter.substring(1)));
excludedDays.add(exclusionDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
for (String timingParameter : timingParameterList) {
GregorianCalendar nextStartByThisParameter = new GregorianCalendar();
nextStartByThisParameter.setTime(now.getTime());
if (timingParameter.startsWith("!")) {
// Exclusions are done previously
continue;
}
else if (!timingParameter.contains(":")) {
if (AgnUtils.isDigit(timingParameter)) {
// daily execusion on given time
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY, Integer.parseInt(timingParameter.substring(0, 2)));
nextStartByThisParameter.set(GregorianCalendar.MINUTE, Integer.parseInt(timingParameter.substring(2)));
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
// Move next start into future (+1 day) until rule is matched
// Move also when meeting holiday rule
while (nextStartByThisParameter.before(now) && nextStartByThisParameter.before(returnStart)
|| AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_MONTH, 1);
} else {
// weekly execution at 00:00 Uhr
List<Integer> weekdayIndexes = new ArrayList<Integer>();
for (String weekDay : AgnUtils.chopToChunks(timingParameter, 2)) {
weekdayIndexes.add(getWeekdayIndex(weekDay));
}
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY,0);
nextStartByThisParameter.set(GregorianCalendar.MINUTE, 0);
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
// Move next start into future (+1 day) until rule is matched
// Move also when meeting holiday rule
while ((nextStartByThisParameter.before(now)
|| !weekdayIndexes.contains(nextStartByThisParameter.get(Calendar.DAY_OF_WEEK))) && nextStartByThisParameter.before(returnStart)
|| AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_MONTH, 1);
}
}
else if (timingParameter.length() == 8) {
// month rule "M01:1700"
String tag = timingParameter.substring(1, timingParameter.indexOf(":"));
String zeit = timingParameter.substring(timingParameter.indexOf(":") + 1);
nextStartByThisParameter.set(GregorianCalendar.DAY_OF_MONTH, Integer.parseInt(tag));
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY, Integer.parseInt(zeit.substring(0, 2)));
nextStartByThisParameter.set(GregorianCalendar.MINUTE, Integer.parseInt(zeit.substring(2)));
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
// find next matching month
while (nextStartByThisParameter.before(now) && nextStartByThisParameter.before(returnStart))
nextStartByThisParameter.add(GregorianCalendar.MONTH, 1);
// Move also when meeting holiday rule
while (AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_YEAR, 1);
}
else if (timingParameter.startsWith("Q:")) {
// quarterly execution (Q:1200) at first day of month
if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.APRIL)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.APRIL);
else if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.JULY)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.JULY);
else if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.OCTOBER)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.OCTOBER);
else {
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.JANUARY);
nextStartByThisParameter.add(GregorianCalendar.YEAR, 1);
}
nextStartByThisParameter.set(GregorianCalendar.DAY_OF_MONTH, 1);
String zeit = timingParameter.substring(timingParameter.indexOf(":") + 1);
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY, Integer.parseInt(zeit.substring(0, 2)));
nextStartByThisParameter.set(GregorianCalendar.MINUTE, Integer.parseInt(zeit.substring(2)));
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
// Move also when meeting holiday rule
while (AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_YEAR, 1);
}
else if (timingParameter.startsWith("QW:")) {
// quarterly execution (QW:1200) at first workingday of month
if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.APRIL)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.APRIL);
else if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.JULY)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.JULY);
else if (nextStartByThisParameter.get(GregorianCalendar.MONTH) < GregorianCalendar.OCTOBER)
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.OCTOBER);
else {
nextStartByThisParameter.set(GregorianCalendar.MONTH, GregorianCalendar.JANUARY);
nextStartByThisParameter.add(GregorianCalendar.YEAR, 1);
}
nextStartByThisParameter.set(GregorianCalendar.DAY_OF_MONTH, 1);
// Move also when meeting holiday rule
while (nextStartByThisParameter.get(GregorianCalendar.DAY_OF_WEEK) == java.util.Calendar.SATURDAY
|| nextStartByThisParameter.get(GregorianCalendar.DAY_OF_WEEK) == java.util.Calendar.SUNDAY
|| AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_MONTH, 1);
String zeit = timingParameter.substring(timingParameter.indexOf(":") + 1);
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY, Integer.parseInt(zeit.substring(0, 2)));
nextStartByThisParameter.set(GregorianCalendar.MINUTE, Integer.parseInt(zeit.substring(2)));
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
}
else {
// weekday execution (also allowes workingday execution Werktagssteuerung)
String wochenTage = timingParameter.substring(0, timingParameter.indexOf(":"));
String zeit = timingParameter.substring(timingParameter.indexOf(":") + 1);
List<Integer> weekdayIndexes = new ArrayList<Integer>();
for (String weekDay : AgnUtils.chopToChunks(wochenTage, 2)) {
weekdayIndexes.add(getWeekdayIndex(weekDay));
}
nextStartByThisParameter.set(GregorianCalendar.HOUR_OF_DAY, Integer.parseInt(zeit.substring(0, 2)));
nextStartByThisParameter.set(GregorianCalendar.MINUTE, Integer.parseInt(zeit.substring(2)));
nextStartByThisParameter.set(GregorianCalendar.SECOND, 0);
nextStartByThisParameter.set(GregorianCalendar.MILLISECOND, 0);
// Move next start into future (+1 day) until rule is matched
// Move also when meeting holiday rule
while ((nextStartByThisParameter.before(now)
|| !weekdayIndexes.contains(nextStartByThisParameter.get(Calendar.DAY_OF_WEEK))) && nextStartByThisParameter.before(returnStart)
|| AgnUtils.dayListIncludes(excludedDays, nextStartByThisParameter))
nextStartByThisParameter.add(GregorianCalendar.DAY_OF_MONTH, 1);
}
if (nextStartByThisParameter.before(returnStart))
returnStart = nextStartByThisParameter;
}
return returnStart.getTime();
}
public static int getWeekdayIndex(String weekday) {
return getWeekdayIndex(weekday, true);
}
public static int getWeekdayIndex(String weekday, boolean useLocaleStringsFirst) {
if (StringUtils.isBlank(weekday)) {
return -1;
} else {
weekday = weekday.toLowerCase().trim();
String[] localeWeekdays = DateFormatSymbols.getInstance().getWeekdays();
for (int i = 0; i < localeWeekdays.length; i++) {
if (localeWeekdays[i].toLowerCase().startsWith(weekday)) {
return i;
}
}
if (weekday.startsWith("so") || weekday.startsWith("su")) {
return Calendar.SUNDAY;
} else if (weekday.startsWith("mo")) {
return Calendar.MONDAY;
} else if (weekday.startsWith("di") || weekday.startsWith("tu")) {
return Calendar.TUESDAY;
} else if (weekday.startsWith("mi") || weekday.startsWith("we")) {
return Calendar.WEDNESDAY;
} else if (weekday.startsWith("do") || weekday.startsWith("th")) {
return Calendar.THURSDAY;
} else if (weekday.startsWith("fr")) {
return Calendar.FRIDAY;
} else if (weekday.startsWith("sa")) {
return Calendar.SATURDAY;
} else {
return -1;
}
}
}
}