docs: private long getScanEndTimeSeconds() {
      // Begin with the raw query end time.
      long end = getEndTime();
  
      // Convert to seconds if we have a query in ms.
      if ((end & Const.SECOND_MASK) != 0L) {
        end /= 1000L;
        if (end - (end * 1000) < 1) {
          // handle an edge case where a user may request a ms time between
          // 0 and 1 seconds. Just bump it a second.
          end++;
        }
      }
      
      if (rollup_query != null) {
        return RollupUtils.getRollupBasetime(end + 
            (rollup_query.getRollupInterval().getIntervalSeconds() * 
                rollup_query.getRollupInterval().getIntervals()), 
            rollup_query.getRollupInterval());
      }
  
      // The calculation depends on whether we're downsampling.
      if (downsampler != null && downsampler.getInterval() > 0) {
        // Downsampling enabled.
        //
        // First, we align the end timestamp to its representative value for the
        // interval FOLLOWING the one in which it appears.
        //
        // OpenTSDB's query bounds are inclusive, but HBase scan bounds are half-
        // open. The user may have provided an end bound that is already
        // interval-aligned (i.e., its interval offset is zero). If so, the user
        // wishes for that interval to appear in the output. In that case, we
        // skip forward an entire extra interval.
        //
        // This can be accomplished by simply not testing for zero offset.
        final long interval_offset = (1000L * end) % downsampler.getInterval();
        final long interval_aligned_ts = end +
          (downsampler.getInterval() - interval_offset) / 1000L;
  
        // Then, if we're now aligned on a timespan boundary, then we need no
        // further adjustment: we are guaranteed to have always moved the end time
        // forward, so the scan will find the data we need.
        //
        // Otherwise, we need to align to the NEXT timespan to ensure that we scan
        // the needed data.
        final long timespan_offset = interval_aligned_ts % Const.MAX_TIMESPAN;
        return (0L == timespan_offset) ?
          interval_aligned_ts :
          interval_aligned_ts + (Const.MAX_TIMESPAN - timespan_offset);
      } else {
        // Not downsampling.
        //
        // Regardless of the end timestamp's position within the current timespan,
        // we must always align to the beginning of the next timespan. This is
        // true even if it's already aligned on a timespan boundary. Again, the
        // reason for this is OpenTSDB's closed interval vs. HBase's half-open.
        final long timespan_offset = end % Const.MAX_TIMESPAN;
        return end + (Const.MAX_TIMESPAN - timespan_offset);
      }
    }