absl::StatusOr IntervalValue::Extract()

in sql_utils/public/interval_value.cc [1063:1125]


absl::StatusOr<int64_t> IntervalValue::Extract(
    functions::DateTimestampPart part) const {
  switch (part) {
    case functions::YEAR:
      return get_months() / kMonthsInYear;
    case functions::MONTH:
      return get_months() % kMonthsInYear;
    case functions::DAY:
      return get_days();
    case functions::HOUR:
      return get_nanos() / kNanosInHour;
    case functions::MINUTE:
      return (get_nanos() % kNanosInHour) / kNanosInMinute;
    case functions::SECOND:
      return (get_nanos() % kNanosInMinute) / kNanosInSecond;
    case functions::MILLISECOND:
      return (get_nanos() % kNanosInSecond) / kNanosInMilli;
    case functions::MICROSECOND:
      return (get_nanos() % kNanosInSecond) / kNanosInMicro;
    case functions::NANOSECOND:
      return (get_nanos() % kNanosInSecond);
    default:
      break;  // fall through
  }

  __int128 total_nanos = get_nanos();
  bool negative_nanos = false;
  if (total_nanos < 0) {
    // Cannot overflow because valid range of nanos is smaller than most
    // negative value.
    total_nanos = -total_nanos;
    negative_nanos = true;
  }
  int64_t value;
  switch (part) {
    case functions::HOUR:
      value = total_nanos / kNanosInHour;
      break;
    case functions::MINUTE:
      value = (total_nanos % kNanosInHour) / kNanosInMinute;
      break;
    case functions::SECOND:
      value = (total_nanos % kNanosInMinute) / kNanosInSecond;
      break;
    case functions::MILLISECOND:
      value = (total_nanos % kNanosInSecond) / kNanosInMilli;
      break;
    case functions::MICROSECOND:
      value = (total_nanos % kNanosInMilli) / kNanosInMicro;
      break;
    case functions::NANOSECOND:
      value = total_nanos % kNanosInMicro;
      break;
    default:
      return absl::OutOfRangeError(
          absl::StrFormat("Unsupported date part %s in EXTRACT FROM INTERVAL",
                          functions::DateTimestampPart_Name(part)));
  }
  if (negative_nanos) {
    value = -value;
  }
  return value;
}