absl::Status ExtractFromDatetime()

in sql_utils/public/functions/date_time_util.cc [2657:2758]


absl::Status ExtractFromDatetime(DateTimestampPart part,
                                 const DatetimeValue& datetime,
                                 int32_t* output) {
  SQL_RET_CHECK(part != TIME)
      << "Use ExtractTimeFromDatetime() for extracting time from datetime";
  if (!datetime.IsValid()) {
    return MakeEvalError() << "Invalid datetime value: "
                           << datetime.DebugString();
  }
  switch (part) {
    case YEAR:
      *output = datetime.Year();
      break;
    case QUARTER:
      *output = (datetime.Month() - 1) / 3 + 1;
      break;
    case MONTH:
      *output = datetime.Month();
      break;
    case DAY:
      *output = datetime.Day();
      break;
    case HOUR:
      *output = datetime.Hour();
      break;
    case MINUTE:
      *output = datetime.Minute();
      break;
    case SECOND:
      *output = datetime.Second();
      break;
    case MILLISECOND:
      *output = datetime.Microseconds() / 1000;
      break;
    case MICROSECOND:
      *output = datetime.Microseconds();
      break;
    case NANOSECOND:
      *output = datetime.Nanoseconds();
      break;
    case DATE:
      SQL_RETURN_IF_ERROR(ConstructDate(datetime.Year(), datetime.Month(),
                                    datetime.Day(), output));
      break;
    case DAYOFWEEK:
      *output = internal_functions::DayOfWeekIntegerSunToSat1To7(
          absl::GetWeekday(absl::CivilDay(datetime.Year(), datetime.Month(),
                                          datetime.Day())));
      break;
    case DAYOFYEAR:
      *output = absl::GetYearDay(
          absl::CivilDay(datetime.Year(), datetime.Month(), datetime.Day()));
      break;
    case WEEK:
    case WEEK_MONDAY:
    case WEEK_TUESDAY:
    case WEEK_WEDNESDAY:
    case WEEK_THURSDAY:
    case WEEK_FRIDAY:
    case WEEK_SATURDAY: {
      const absl::CivilDay first_calendar_day_of_year(datetime.Year(), 1, 1);

      SQL_ASSIGN_OR_RETURN(const absl::Weekday weekday,
                       GetFirstWeekDayOfWeek(part));
      const absl::CivilDay effective_first_day_of_year =
          NextWeekdayOrToday(first_calendar_day_of_year, weekday);

      const absl::CivilDay day(datetime.Year(), datetime.Month(),
                               datetime.Day());
      if (day < effective_first_day_of_year) {
        *output = 0;
      } else {
        // cast is safe, guaranteed to be less than 52.
        *output =
            static_cast<int32_t>(((day - effective_first_day_of_year) / 7) + 1);
      }
      break;
    }
    case ISOYEAR:
      // cast is safe, year "guaranteed" safe by method contract.
      *output = static_cast<int32_t>(GetIsoYear(
          absl::CivilDay(datetime.Year(), datetime.Month(), datetime.Day())));
      break;
    case ISOWEEK:
      *output = GetIsoWeek(
          absl::CivilDay(datetime.Year(), datetime.Month(), datetime.Day()));
      break;
    case DATETIME:
      return MakeEvalError()
             << "Unsupported DateTimestampPart " << DateTimestampPart_Name(part)
             << " to extract from datetime";
    case TIME:
      // Should never reach this.
      SQL_RET_CHECK_FAIL()
          << "Use ExtractTimeFromDatetime() for extracting time from datetime";
      break;
    default:
      return MakeEvalError()
             << "Unexpected DateTimestampPart " << DateTimestampPart_Name(part);
  }
  return absl::OkStatus();
}