1

I want to iterate between two specific dates and store all the corresponding 10-minute values in an ArrayList. I followed the answers and code examples in the Get all full hours of every day of a year thread but I'm having problems in customizing the code to my needs. My code is the following so far:

final DateFormat df = DateFormat.getDateTimeInstance();
    final Calendar c = Calendar.getInstance();
    c.clear();
    for (c.set(StringDateUtils.getYear(earliestKey), (StringDateUtils.getMonth(earliestKey) - 1), 
            StringDateUtils.getDayOfMonth(earliestKey), StringDateUtils.getHourOfDay(earliestKey), 
            StringDateUtils.getMinuteOfHour(earliestKey));

            c.get(Calendar.YEAR) <= StringDateUtils.getYear(latestKey) && 
            c.get(Calendar.MONTH) <= (StringDateUtils.getMonth(latestKey) - 1) && 
            c.get(Calendar.DAY_OF_MONTH) <= StringDateUtils.getDayOfMonth(latestKey) && 
            c.get(Calendar.HOUR) <= StringDateUtils.getHourOfDay(latestKey) && 
            c.get(Calendar.MINUTE) <= StringDateUtils.getMinuteOfHour(latestKey);

            c.add(Calendar.MINUTE, 10)) {
        System.out.println(df.format(c.getTime()));
    }

earliestKey contains a String with earliest Date and latestKey a String with the latest Date. StringDateUtils is a custom written class that contains all auxiliary methods to get the year, month etc from a String that is assembled in YYYYMMDD_HHMM fashion. I have also checked the values of earliestKey and latestKey to be valid in the aforementioned form and everything seems OK. The problem, as I can understand, is in the second part of the loop condition, the one that in the classic loop-iterations is the break-condition. I have tried '!=' instead of inequality, OR instead of AND operator but I can't get it to work. The following code snipped does not enter not even the first iteration.

Community
  • 1
  • 1
Lefteris008
  • 899
  • 3
  • 10
  • 29
  • 1
    You need to replace the `;` at the end of your `for` loop declaration with a `{` – Sean Bright Jan 11 '16 at 17:55
  • Your approach works like a charm [demo](http://ideone.com/8n5baE). Voting to close as cannot reproduce / typo. – Sergey Kalinichenko Jan 11 '16 at 18:00
  • @dasblinkenlight Incorrect. If start is `2015-11-20 00:00` and end is `2015-11-31 09:50`, it will stop after `2015-11-20 09:50`, when the hour-condition goes false the first time. – Andreas Jan 11 '16 at 18:26

1 Answers1

2

The looping condition is invalid. When comparing against a compound value, you need to only compare secondary values when all preceding values are equal.

E.g. if ending values are endA, endB, and endC, then condition should be:

a < endA || (a == endA && (b < endB || (b == endB && c <= endC)))

However, for better performance, you should resolve the end condition into a single value that can easily be tested:

final DateFormat df = DateFormat.getDateTimeInstance();
final Calendar c = Calendar.getInstance();
c.clear();
c.set(StringDateUtils.getYear(latestKey),
      StringDateUtils.getMonth(latestKey) - 1, 
      StringDateUtils.getDayOfMonth(latestKey),
      StringDateUtils.getHourOfDay(latestKey),
      StringDateUtils.getMinuteOfHour(latestKey));
long endMillis = c.getTimeInMillis();
c.clear();
c.set(StringDateUtils.getYear(earliestKey),
      StringDateUtils.getMonth(earliestKey) - 1,
      StringDateUtils.getDayOfMonth(earliestKey),
      StringDateUtils.getHourOfDay(earliestKey),
      StringDateUtils.getMinuteOfHour(earliestKey));
for (; c.getTimeInMillis() <= endMillis; c.add(Calendar.MINUTE, 10))
    System.out.println(df.format(c.getTime()));

Now, since StringDateUtils is a homegrown helper class, you should add a helper for setting a Calendar, in which case you end up with:

final DateFormat df = DateFormat.getDateTimeInstance();
final Calendar c = Calendar.getInstance();
StringDateUtils.clearAndSetYearToMinute(c, latestKey);
long endMillis = c.getTimeInMillis();
StringDateUtils.clearAndSetYearToMinute(c, earliestKey);
for (; c.getTimeInMillis() <= endMillis; c.add(Calendar.MINUTE, 10))
    System.out.println(df.format(c.getTime()));

If using Java 8+, you should use the new java.time:

final DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
ZonedDateTime endDateTime = StringDateUtils.getZonedDateMinute(latestKey);
ZonedDateTime dateTime = StringDateUtils.getZonedDateMinute(earliestKey);
for (; ! dateTime.isAfter(endDateTime); dateTime = dateTime.plusMinutes(10)) {
    System.out.println(dateTime.format(formatter));
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thanks for your answer, I'll update the StringDateUtils class according to your propositions. Just to clarify, the problem was that I kept using c both for start and for end conditions in my for-loop? – Lefteris008 Jan 12 '16 at 11:44
  • 1
    @PiXel1225 No, you problem was that your loop condition was `a <= endA && b <= endB && c <= endC`, which is incorrect. See beginning of answer. Fixing that would make a very complex condition, so I suggested a much simpler alternative, that also performs much better. – Andreas Jan 12 '16 at 17:27