static absl::Status TruncateDateImpl()

in sql_utils/public/functions/date_time_util.cc [1318:1376]


static absl::Status TruncateDateImpl(int32_t date, DateTimestampPart part,
                                     bool enforce_range, int32_t* output) {
  if (!IsValidDate(date)) {
    return MakeEvalError() << "Invalid date value: " << date;
  }
  absl::CivilDay civil_day = EpochDaysToCivilDay(date);
  switch (part) {
    case YEAR:
      *output = CivilDayToEpochDays(absl::CivilDay(civil_day.year(), 1, 1));
      break;
    case ISOYEAR: {
      *output = CivilDayToEpochDays(
          date_time_util_internal::GetFirstDayOfIsoYear(civil_day));
      break;
    }
    case MONTH: {
      *output = CivilDayToEpochDays(
          absl::CivilDay(civil_day.year(), civil_day.month(), 1));
      break;
    }
    case QUARTER: {
      int m = civil_day.month();
      m = (m - 1) / 3 * 3 + 1;
      *output = CivilDayToEpochDays(absl::CivilDay(civil_day.year(), m, 1));
      break;
    }
    case WEEK:
    case ISOWEEK:
    case WEEK_MONDAY:
    case WEEK_TUESDAY:
    case WEEK_WEDNESDAY:
    case WEEK_THURSDAY:
    case WEEK_FRIDAY:
    case WEEK_SATURDAY: {
      SQL_ASSIGN_OR_RETURN(const absl::Weekday first_day_of_week,
                       GetFirstWeekDayOfWeek(part));
      *output =
          CivilDayToEpochDays(PrevWeekdayOrToday(civil_day, first_day_of_week));
      break;
    }
    case DAY:
      *output = date;  // nothing to truncate.
      break;
    default:
      return MakeEvalError() << "Unsupported DateTimestampPart "
                             << DateTimestampPart_Name(part);
  }
  // Truncating to WEEK and WEEK(<WEEKDAY>) can result in a date that is out
  // of bounds (i.e., before 0001-01-01), so we check the truncated date
  // result here. The other date parts do not have the potential to underflow,
  // but we validate the result anyway as a sanity check.
  if (enforce_range && !IsValidDate(*output)) {
    return MakeEvalError() << "Truncating date " << DateErrorString(date)
                           << " to " << DateTimestampPartToSQL(part)
                           << " resulted in an out of range date value: "
                           << *output;
  }
  return absl::OkStatus();
}