private Object getOffsetInfo(LocalDateTime dt) {

    // check if using last rules
    if (this.lastRules.length > 0 && dt.isAfter(this.savingsLocalTransitions[this.savingsLocalTransitions.length - 1])) {
      ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear());
      Object info = null;
      for (ZoneOffsetTransition trans : transArray) {
        info = findOffsetInfo(dt, trans);
        if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) {
          return info;
        }
      }
      return info;
    }

    // using historic rules
    int index = Arrays.binarySearch(this.savingsLocalTransitions, dt);
    if (index == -1) {
      // before first transition
      return this.wallOffsets[0];
    }
    if (index < 0) {
      // switch negative insert position to start of matched range
      index = -index - 2;
    } else if (index < this.savingsLocalTransitions.length - 1
        && this.savingsLocalTransitions[index].equals(this.savingsLocalTransitions[index + 1])) {
      // handle overlap immediately following gap
      index++;
    }
    if ((index & 1) == 0) {
      // gap or overlap
      LocalDateTime dtBefore = this.savingsLocalTransitions[index];
      LocalDateTime dtAfter = this.savingsLocalTransitions[index + 1];
      ZoneOffset offsetBefore = this.wallOffsets[index / 2];
      ZoneOffset offsetAfter = this.wallOffsets[index / 2 + 1];
      if (offsetAfter.getTotalSeconds() > offsetBefore.getTotalSeconds()) {
        // gap
        return new ZoneOffsetTransition(dtBefore, offsetBefore, offsetAfter);
      } else {
        // overlap
        return new ZoneOffsetTransition(dtAfter, offsetBefore, offsetAfter);
      }
    } else {
      // normal (neither gap or overlap)
      return this.wallOffsets[index / 2 + 1];
    }
  }