1919import com .bc .calvalus .commons .DateRange ;
2020import com .bc .calvalus .commons .DateUtils ;
2121
22+ import java .text .ParseException ;
23+ import java .text .SimpleDateFormat ;
2224import java .util .ArrayList ;
2325import java .util .Calendar ;
2426import java .util .Date ;
2527import java .util .GregorianCalendar ;
2628import java .util .List ;
29+ import java .util .TimeZone ;
2730import java .util .regex .Matcher ;
2831import java .util .regex .Pattern ;
2932
@@ -46,6 +49,23 @@ public static List<DateRange> fromDateList(Date... dateList) {
4649 return dateRangeList ;
4750 }
4851
52+ private static final SimpleDateFormat ISO_DATE_FORMAT = new SimpleDateFormat ("yyyy-MM-dd" );
53+ static {
54+ ISO_DATE_FORMAT .setTimeZone (TimeZone .getTimeZone ("UTC" ));
55+ }
56+
57+ private static String dateStringOf (Date date ) {
58+ return ISO_DATE_FORMAT .format (date );
59+ }
60+
61+ private static Date dateOf (String date ) {
62+ try {
63+ return ISO_DATE_FORMAT .parse (date );
64+ } catch (ParseException e ) {
65+ throw new RuntimeException ("failed to parse " + date , e );
66+ }
67+ }
68+
4969 /**
5070 * By default the stepping and compositing periods are given in full days.
5171 * Additional the periods can be specified in weeks (using "w" as suffix),
@@ -56,9 +76,59 @@ public static List<DateRange> fromDateList(Date... dateList) {
5676 * The week containing the 30 Dec is 8 days long to include the 31 Dec, too.
5777 * In leap years the week containing the 28 Feb is 8 days long
5878 * to include the 29 Feb, too.
59- * If you dont 't want this behaviour you can specify 7 days as period instead.
79+ * If you don 't want this behaviour you can specify 7 days as period instead.
6080 *
6181 */
82+ public static String periodicalDateRanges (String min , String max , String steppingPeriodLength , String compositingPeriodLength ) {
83+ StringBuilder accu = new StringBuilder ();
84+ GregorianCalendar cursor = new GregorianCalendar (TimeZone .getTimeZone ("UTC" ));
85+ cursor .setTime (dateOf (min ));
86+ GregorianCalendar end = new GregorianCalendar (TimeZone .getTimeZone ("UTC" ));
87+ end .setTime (dateOf (max ));
88+ end .add (Calendar .DAY_OF_MONTH , 1 );
89+
90+ Period steppingPeriod = parsePeriod (steppingPeriodLength );
91+ Period compositingPeriod = parsePeriod (compositingPeriodLength );
92+
93+ while (true ) {
94+
95+ // determine start and end of period
96+ final Date periodStart = cursor .getTime ();
97+ compositingPeriod .next (cursor );
98+ cursor .add (Calendar .SECOND , -1 );
99+ final Date periodEnd = cursor .getTime ();
100+ // check whether end of period exceeds end of overall interval
101+ if (cursor .after (end )) {
102+ break ;
103+ }
104+ if (accu .length () > 0 ) {
105+ accu .append ("," );
106+ }
107+ accu .append ('[' );
108+ accu .append (dateStringOf (periodStart ));
109+ accu .append (":" );
110+ accu .append (dateStringOf (cursor .getTime ()));
111+ accu .append ("]" );
112+ // proceed by one period length
113+ cursor .setTime (periodStart );
114+ steppingPeriod .next (cursor );
115+ }
116+ return accu .toString ();
117+ }
118+
119+ /**
120+ * By default the stepping and compositing periods are given in full days.
121+ * Additional the periods can be specified in weeks (using "w" as suffix),
122+ * month (using "m" as suffix) or years (using "y" as suffix).
123+ * <p>
124+ * The weekly option extends 2 weeks of the year to being 8 days long to
125+ * get a continuous stepping over multiple years.
126+ * The week containing the 30 Dec is 8 days long to include the 31 Dec, too.
127+ * In leap years the week containing the 28 Feb is 8 days long
128+ * to include the 29 Feb, too.
129+ * If you don't want this behaviour you can specify 7 days as period instead.
130+ *
131+ */
62132 public static List <DateRange > fromMinMax (Date minDate , Date maxDate , String steppingPeriodLength , String compositingPeriodLength ) {
63133 List <DateRange > dateRangeList = new ArrayList <>();
64134
0 commit comments