absl::Status LastDayOfDate()

in sql_utils/public/functions/date_time_util.cc [1378:1444]


absl::Status LastDayOfDate(int32_t date, DateTimestampPart part,
                           int32_t* output) {
  if (!IsValidDate(date)) {
    return MakeEvalError() << "Invalid date value: " << date;
  }
  absl::CivilDay civil_day = EpochDaysToCivilDay(date);
  // For YEAR, MONTH, QUARTER, last_day is implemented by first calling AddDate
  // to add 1 to the part of the date, then truncate the date in the part,
  // finally subtract 1 day
  // However, AddDate may overflow for some input dates that can return a valid
  // last_day result, so those cases are handled first.
  if (civil_day.year() == 9999) {
    if (part == YEAR || (part == MONTH && civil_day.month() == 12) ||
        (part == QUARTER && civil_day.month() >= 10 &&
         civil_day.month() <= 12)) {
      *output = CivilDayToEpochDays(absl::CivilDay(9999, 12, 31));
      return absl::OkStatus();
    }
  }
  switch (part) {
    case YEAR:
    case MONTH:
    case QUARTER: {
      SQL_RETURN_IF_ERROR(AddDate(date, part, 1, &date));
      SQL_RETURN_IF_ERROR(
          TruncateDateImpl(date, part, /*enforce_range=*/false, &date));
      SQL_RETURN_IF_ERROR(SubDate(date, DAY, 1, output));
      break;
    }
    case ISOYEAR: {
      // last day of ISOYEAR could out of range if the input is 9999,
      // the last day of ISOYEAR 9999 is 10000-01-02
      *output = CivilDayToEpochDays(
          date_time_util_internal::GetLastDayOfIsoYear(civil_day));
      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)) +
                6;
      break;
    }
    default:
      return MakeEvalError() << "Unsupported DateTimestampPart "
                             << DateTimestampPart_Name(part);
  }
  // ISO_YEAR, WEEK and WEEK(<WEEKDAY>) as part can result in a date that is out
  // of bounds (i.e., after 9999-12-31), so we check the last day
  // result here. The other date parts do not have the potential to underflow,
  // but we validate the result anyway as a sanity check.
  if (!IsValidDate(*output)) {
    return MakeEvalError() << "Last day of date " << DateErrorString(date)
                           << " to " << DateTimestampPartToSQL(part)
                           << " resulted in an out of range date value: "
                           << *output;
  }
  return absl::OkStatus();
}