# HG changeset patch # User Tom Gottfried # Date 1475158538 -7200 # Node ID 8ec6a2a3117199107314d87b8a9452a3333cc426 # Parent 7788a805a98df8214a96bc1d2fc0aa9a87bc6ecf Generalize generation of Proben for (multiples of) months. diff -r 7788a805a98d -r 8ec6a2a31171 src/main/java/de/intevation/lada/factory/ProbeFactory.java --- a/src/main/java/de/intevation/lada/factory/ProbeFactory.java Tue Sep 27 16:16:31 2016 +0200 +++ b/src/main/java/de/intevation/lada/factory/ProbeFactory.java Thu Sep 29 16:15:38 2016 +0200 @@ -12,6 +12,7 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Hashtable; import javax.inject.Inject; @@ -44,6 +45,143 @@ */ public class ProbeFactory { + private static Hashtable fieldsTable; + + public ProbeFactory() { + int[] M = { Calendar.MONTH, Calendar.DAY_OF_MONTH, 1 }; + int[] Q = { Calendar.MONTH, Calendar.DAY_OF_MONTH, 3 }; + int[] H = { Calendar.MONTH, Calendar.DAY_OF_MONTH, 6 }; + + this.fieldsTable = new Hashtable(); + + this.fieldsTable.put("M", M); + this.fieldsTable.put("Q", Q); + this.fieldsTable.put("H", H); + } + + private class Intervall { + private int teilVon; + private int teilBis; + private int offset; + + private int intervallField; + private int subIntField; + private int intervallFactor; + + private Calendar from; + + public Intervall( + Messprogramm messprogramm, + Calendar start + ) { + this.teilVon = messprogramm.getTeilintervallVon(); + this.teilBis = messprogramm.getTeilintervallBis(); + this.offset = messprogramm.getIntervallOffset(); + + this.intervallField = fieldsTable + .get(messprogramm.getProbenintervall())[0]; + this.subIntField = fieldsTable + .get(messprogramm.getProbenintervall())[1]; + this.intervallFactor = fieldsTable + .get(messprogramm.getProbenintervall())[2]; + + /* Align with beginning of next interval + * like first day of next quarter.*/ + // TODO: Avoid overflow e.g. into next quarter, if e.g. teilBis + // greater than sum of actual maxima of months in quarter. + int startIntField = start.get(intervallField); + this.from = (Calendar)start.clone(); + from.set( + intervallField, + startIntField + startIntField % intervallFactor + ); + from = adjustSubIntField(from, teilVon); + if (start.after(from)) { + // to next intervall if start not at first day of intervall + this.roll(); + } + } + + /** + * Return given calendar adjusted to start of intervall (e.g. first + * day in quarter) plus offset and given amount of days. + * + * @param cal Calendar to be adjusted + * @param int amount of days to be added (plus offset) + * + * @return the adjusted Calendar object. + */ + private Calendar adjustSubIntField(Calendar cal, int teil) { + int intField = cal.get(intervallField); + cal.set( + intervallField, + intField - intField % intervallFactor + ); + cal.set(subIntField, offset + Math.min(teil, getDuration())); + return cal; + } + + /** + * Get sum of actual maxima for given field from actual field value + * for the next factor values of iterField. + * + * @param calendar Time to start from + * + * @return the sum of maxima for the field values specified with + * field and factor. + */ + private int getDuration() { + logger.debug("## calculate maximum ##"); + int duration = 0; + Calendar tmp = (Calendar)from.clone(); + /* reset to beginning of intervall, e.g. first day of quarter + * to compensate possible overflow if + * teilVon > maximum of intervallField: */ + int fromIntField = from.get(intervallField); + tmp.set( + intervallField, + fromIntField - fromIntField % intervallFactor + ); + tmp.set(subIntField, tmp.getActualMinimum(subIntField)); + logger.debug(tmp); + for (int i = 0; i < intervallFactor; i++) { + logger.debug(tmp.getActualMaximum(subIntField)); + duration += tmp.getActualMaximum(subIntField); + tmp.add(intervallField, 1); + } + logger.debug(duration); + return duration; + } + + public Date getFrom() { + logger.debug("getFrom() from: " + from); + return from.getTime(); + } + + public Date getTo() { + logger.debug("getTo() from: " + from); + Calendar to = (Calendar)from.clone(); + to = adjustSubIntField(to, teilBis); + return to.getTime(); + } + + public boolean startInLeapYear() { + return from.getActualMaximum(Calendar.DAY_OF_YEAR) > 364; + } + + public int getStartDOY() { + return from.get(Calendar.DAY_OF_YEAR); + } + + public void roll() { + from.add(intervallField, intervallFactor); + from = adjustSubIntField(from, teilVon); + } + + } + // end Intervall class + + @Inject Logger logger; /** @@ -80,20 +218,11 @@ start.setTimeInMillis(from); Calendar end = Calendar.getInstance(); end.setTimeInMillis(to); + List proben = new ArrayList(); - - if ("M".equals(messprogramm.getProbenintervall())) { - Calendar realStart = getStart ("M", start); - proben.addAll(generateMonth(messprogramm, realStart, end)); - } - else if ("Q".equals(messprogramm.getProbenintervall())) { - Calendar realStart = getStart ("Q", start); - proben.addAll(generateQuarter(messprogramm, realStart, end)); - } - else if ("H".equals(messprogramm.getProbenintervall())) { - Calendar realStart = getStart ("H", start); - proben.addAll(generateHalf(messprogramm, realStart, end)); + if (fieldsTable.keySet().contains(messprogramm.getProbenintervall())) { + proben.addAll(generateMonthly(messprogramm, start, end)); } else { Date[][] intervals = calculateIntervals(start, end, messprogramm); @@ -161,44 +290,28 @@ } } - private List generateMonth( + private List generateMonthly( Messprogramm messprogramm, Calendar start, Calendar end ) { + logger.debug("start: " + start); + int gueltigVon = messprogramm.getGueltigVon(); int gueltigBis = messprogramm.getGueltigBis(); - int offset = messprogramm.getIntervallOffset(); - int teilVon = messprogramm.getTeilintervallVon(); - int teilBis = messprogramm.getTeilintervallBis(); - List proben = new ArrayList(); - // Create template Calendars to be recomputed/adapted to actual - // maxima/minima of fields. - Calendar initSolldatumBeginn = (Calendar)start.clone(); - initSolldatumBeginn.set(Calendar.DAY_OF_MONTH, offset + teilVon); - Calendar initSolldatumEnde = (Calendar)start.clone(); - initSolldatumEnde.set(Calendar.DAY_OF_MONTH, offset + teilBis); - - // Initialize solldatum values for Probe objects, i.e. trigger - // recomputation of Calendar fields. - Calendar solldatumBeginn = (Calendar)initSolldatumBeginn.clone(); - Calendar solldatumEnde = (Calendar)initSolldatumEnde.clone(); - solldatumBeginn.add(Calendar.MONTH, 0); - solldatumEnde.add(Calendar.MONTH, 0); - - for (int monthCount = 1; solldatumBeginn.before(end); monthCount++) { + for (Intervall intervall = new Intervall(messprogramm, start); + intervall.getFrom().before(end.getTime()); + intervall.roll() + ) { /* Leap year adaption of validity period. * It is assumed here (and should be enforced by the data model) * that gueltigVon and gueltigBis are always given relative to * a non-leap year. E.g. a value of 59 is assumed to denote * March 1 and thus has to be adapted in a leap year. */ - int leapDay = - solldatumBeginn.getActualMaximum(Calendar.DAY_OF_YEAR) > 364 - ? 1 - : 0; + int leapDay = intervall.startInLeapYear() ? 1 : 0; int actualGueltigVon = gueltigVon > 58 ? gueltigVon + leapDay @@ -208,7 +321,7 @@ ? gueltigBis + leapDay : gueltigBis; - int solldatumBeginnDOY = solldatumBeginn.get(Calendar.DAY_OF_YEAR); + int solldatumBeginnDOY = intervall.getStartDOY(); if (( // Validity within one year @@ -224,113 +337,16 @@ ) { LProbe probe = createObjects( messprogramm, - solldatumBeginn.getTime(), - solldatumEnde.getTime() + intervall.getFrom(), + intervall.getTo() ); if (probe != null) { proben.add(probe); } - } - - // Reset solldatumBeginn to align DAY_OF_MONTH with initial value - solldatumBeginn = (Calendar)initSolldatumBeginn.clone(); - solldatumEnde = (Calendar)initSolldatumEnde.clone(); - - // Move to next month. - // This may change DAY_OF_MONTH due to actual maximum. - solldatumBeginn.add(Calendar.MONTH, monthCount); - solldatumEnde.add(Calendar.MONTH, monthCount); - } - - return proben; - } - - private List generateQuarter( - Messprogramm messprogramm, - Calendar start, - Calendar end - ) { - int offset = messprogramm.getIntervallOffset(); - int teilVon = messprogramm.getTeilintervallVon() - 1; - int teilBis = messprogramm.getTeilintervallBis(); - int manualDuration = teilBis - teilVon; - - List proben = new ArrayList(); - - int currentLength = getDurationQuarter(start); - if (manualDuration > 0) { - currentLength = manualDuration; - } - Calendar quarterStart = (Calendar)start.clone(); - Calendar quarterEnd = Calendar.getInstance(); - quarterStart.add(Calendar.DAY_OF_YEAR, offset + teilVon); - quarterEnd.setTime(start.getTime()); - quarterEnd.add(Calendar.DAY_OF_YEAR, currentLength); - for (;quarterStart.before(end);) { - int startDOY = quarterStart.get(Calendar.DAY_OF_YEAR); - if (startDOY > messprogramm.getGueltigVon() - && startDOY < messprogramm.getGueltigBis()) { - LProbe probe = createObjects( - messprogramm, - quarterStart.getTime(), - quarterEnd.getTime() - ); - if (probe != null) { - proben.add(probe); - } + } else { + logger.debug(solldatumBeginnDOY + " not within validity " + + actualGueltigVon + " to " + actualGueltigBis); } - quarterStart.set(Calendar.DAY_OF_MONTH, 2); - quarterStart = getStart("Q", quarterStart); - quarterStart.add(Calendar.DAY_OF_YEAR, offset + teilVon); - if (manualDuration <= 0) { - currentLength = getDurationQuarter(quarterStart); - } - quarterEnd.setTime(quarterStart.getTime()); - quarterEnd.add(Calendar.DAY_OF_YEAR, currentLength); - } - - return proben; - } - - private List generateHalf( - Messprogramm messprogramm, - Calendar start, - Calendar end - ) { - int offset = messprogramm.getIntervallOffset(); - int teilVon = messprogramm.getTeilintervallVon() - 1; - int teilBis = messprogramm.getTeilintervallBis(); - int manualDuration = teilBis - teilVon; - - List proben = new ArrayList(); - - int currentLength = getDurationHalf(start); - if (manualDuration > 0) { - currentLength = manualDuration; - } - Calendar halfStart = (Calendar)start.clone(); - Calendar halfEnd = Calendar.getInstance(); - halfStart.add(Calendar.DAY_OF_YEAR, offset + teilVon); - halfEnd.setTime(halfStart.getTime()); - halfEnd.add(Calendar.DAY_OF_YEAR, currentLength); - for (;halfStart.before(end);) { - int startDOY = halfStart.get(Calendar.DAY_OF_YEAR); - if (startDOY > messprogramm.getGueltigVon() - && startDOY < messprogramm.getGueltigBis()) { - LProbe probe = createObjects( - messprogramm, halfStart.getTime(), halfEnd.getTime()); - if (probe != null) { - proben.add(probe); - } - } - halfStart.set(Calendar.DAY_OF_MONTH, 2); - halfStart = getStart("H", halfStart); - halfStart.add(Calendar.DAY_OF_YEAR, offset + teilVon); - if (manualDuration <= 0) { - currentLength = getDurationHalf(halfStart); - } - halfEnd.setTime(halfStart.getTime()); - halfEnd.add(Calendar.DAY_OF_YEAR, currentLength); } return proben; @@ -368,97 +384,6 @@ return proben; } - private int getDurationMonth(Calendar month) { - return month.getActualMaximum(Calendar.DAY_OF_MONTH); - } - - private int getDurationQuarter(Calendar month) { - if ((month.get(Calendar.MONTH)) % 3 != 0) { - logger.debug("not a valid month!"); - return 91; // Fallback to not generate to much probe objects. - } - int duration = 0; - Calendar tmp = (Calendar)month.clone(); - for (int i = 0; i < 3; i++) { - duration += tmp.getActualMaximum(Calendar.DAY_OF_MONTH); - tmp.set(Calendar.MONTH, tmp.get(Calendar.MONTH) + 1); - } - return duration; - } - - private int getDurationHalf(Calendar month) { - if ((month.get(Calendar.MONTH)) % 6 != 0) { - logger.debug("not a valid month!"); - return 183; // Fallback to not generate to much probe objects. - } - int duration = 0; - Calendar tmp = (Calendar)month.clone(); - for (int i = 0; i < 6; i++) { - duration += tmp.getActualMaximum(Calendar.DAY_OF_MONTH); - tmp.set(Calendar.MONTH, tmp.get(Calendar.MONTH) + 1); - } - return duration - 1; - } - - private Calendar getStart(String interval, Calendar date) { - Calendar start = Calendar.getInstance(); - start.setTime(date.getTime()); - if ("M".equals(interval)) { - if (start.get(Calendar.DAY_OF_MONTH) > 1) { - int month = start.get(Calendar.MONTH) + 1; - start.set(Calendar.MONTH, month); - start.set(Calendar.DAY_OF_MONTH, 1); - } - } - else if ("Q".equals(interval)) { - int month = start.get(Calendar.MONTH); /* 0 through 11 */ - int quarter = (month / 3) + 1; - Calendar tmp = (Calendar)start.clone(); - logger.debug("in " + quarter + ". quarter"); - - tmp.set(Calendar.MONTH, (quarter * 3)); - logger.debug("its the " + tmp.get(Calendar.MONTH) + ". month"); - tmp.set(Calendar.DAY_OF_MONTH, 1); - int firstDayOfQuarter = tmp.get(Calendar.DAY_OF_YEAR); - if (start.get(Calendar.DAY_OF_YEAR) > firstDayOfQuarter) { - if (quarter < 4) { - start.set(Calendar.MONTH, (quarter + 1) * 3 - 2); - start.set(Calendar.DAY_OF_MONTH, 1); - } - else { - // Next year... - start.set(Calendar.MONTH, 0); - start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1); - start.set(Calendar.DAY_OF_MONTH, 1); - } - } - else { - start = (Calendar)tmp.clone(); - } - } - else if ("H".equals(interval)) { - int month = start.get(Calendar.MONTH); - int half = (month / 6) + 1; - Calendar tmp = (Calendar)start.clone(); - tmp.set(Calendar.MONTH, half * 6 - 6); - tmp.set(Calendar.DAY_OF_MONTH, 1); - int firstDayOfHalf = tmp.get(Calendar.DAY_OF_YEAR); - if (start.get(Calendar.DAY_OF_YEAR) > firstDayOfHalf) { - if (half == 1) { - start.set(Calendar.MONTH, (half + 1) * 6 - 6); - start.set(Calendar.DAY_OF_MONTH, 1); - } - else { - // Next year... - start.set(Calendar.MONTH, 0); - start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1); - start.set(Calendar.DAY_OF_MONTH, 1); - } - } - } - return start; - } - private Calendar getMonday(Calendar week) { if (week.get(Calendar.DAY_OF_WEEK) > 1) { week.set(Calendar.WEEK_OF_YEAR, @@ -651,43 +576,6 @@ return intervals; } - /** - * Parse an interval string. - * Posible values are: J, H, Q, M, W4, W2, W, T - * - * @param interval the interval string. - * - * @return the amount of days for the given interval. - */ - private int parseInterval(String interval) { - if ("J".equals(interval)) { - return 365; - } - else if ("H".equals(interval)) { - return 183; - } - else if ("Q".equals(interval)) { - return 91; - } - else if ("M".equals(interval)) { - return 30; - } - else if ("W4".equals(interval)) { - return 28; - } - else if ("W2".equals(interval)) { - return 14; - } - else if ("W".equals(interval)) { - return 7; - } - else if ("T".equals(interval)) { - return 1; - } - else { - return 0; - } - } /** * Search for the umwelt id using the 'deskriptor'. @@ -737,6 +625,7 @@ return messprogramm; } + /** * Find the umwelt id for a given deskriptor. *