@Override
  public boolean hasNextTimeRange() {
    if (hasCachedTimeRange) {
      return true;
    }
    if (curTimeRange == null) {
      curTimeRange = getFirstTimeRange();
      timeRangeCount++;
      hasCachedTimeRange = true;
      return true;
    }

    long retStartTime;
    long retEndTime;
    long curStartTime = curTimeRange.getMin();
    if (isAscending) {
      if (slidingStep.containsMonth()) {
        retStartTime =
            DateTimeUtils.calcPositiveIntervalByMonth(
                startTime, slidingStep.multiple(timeRangeCount), zoneId);
      } else {
        retStartTime = curStartTime + slidingStep.nonMonthDuration;
      }
      // This is an open interval , [0-100)
      if (retStartTime >= endTime) {
        return false;
      }
    } else {
      if (slidingStep.containsMonth()) {
        // group by month doesn't support ascending.
        throw new UnsupportedOperationException(
            "Ascending is not supported when sliding step contains month.");
      } else {
        retStartTime = curStartTime - slidingStep.nonMonthDuration;
      }
      if (retStartTime < startTime) {
        return false;
      }
    }

    if (interval.containsMonth()) {
      retEndTime =
          DateTimeUtils.calcPositiveIntervalByMonth(
              startTime, slidingStep.multiple(timeRangeCount).merge(interval), zoneId);
    } else {
      retEndTime = retStartTime + interval.nonMonthDuration;
    }
    retEndTime = Math.min(retEndTime, endTime);
    curTimeRange = new TimeRange(retStartTime, retEndTime);
    hasCachedTimeRange = true;
    timeRangeCount++;
    return true;
  }
This class iteratively generates aggregated time windows.

<p>For example, startTime = 0, endTime = 10, interval = 5, slidingStep = 3, leftCloseRightOpen,
return [0,5],[3,7],[6,9],[9,9]
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/aggregation/timerangeiterator/AggrWindowIterator.java