in sql_utils/public/functions/date_time_util.cc [3104:3166]
absl::Status DiffDates(int32_t date1, int32_t date2, DateTimestampPart part,
int32_t* output) {
if (!IsValidDate(date1)) {
return MakeEvalError() << "Invalid date value: " << date1;
}
if (!IsValidDate(date2)) {
return MakeEvalError() << "Invalid date value: " << date2;
}
switch (part) {
case DAY:
*output = date1 - date2;
break;
case WEEK:
case WEEK_MONDAY:
case WEEK_TUESDAY:
case WEEK_WEDNESDAY:
case WEEK_THURSDAY:
case WEEK_FRIDAY:
case WEEK_SATURDAY:
case ISOWEEK:
SQL_RETURN_IF_ERROR(
TruncateDateImpl(date1, part, /*enforce_range=*/false, &date1));
SQL_RETURN_IF_ERROR(
TruncateDateImpl(date2, part, /*enforce_range=*/false, &date2));
*output = (date1 - date2) / 7;
break;
case YEAR:
case ISOYEAR:
case QUARTER:
case MONTH: {
absl::CivilDay civil_day1 = EpochDaysToCivilDay(date1);
absl::civil_year_t y1 = civil_day1.year();
int32_t m1 = civil_day1.month();
absl::CivilDay civil_day2 = EpochDaysToCivilDay(date2);
absl::civil_year_t y2 = civil_day2.year();
int32_t m2 = civil_day2.month();
switch (part) {
case YEAR:
*output = y1 - y2;
break;
case ISOYEAR:
// cast is safe because dates are severely restricted by IsValidDate.
*output = static_cast<int32_t>(GetIsoYear(civil_day1) -
GetIsoYear(civil_day2));
break;
case MONTH:
*output = (y1 - y2) * 12 + (m1 - m2);
break;
case QUARTER:
*output = (y1 * 12 + m1 - 1) / 3 - (y2 * 12 + m2 - 1) / 3;
break;
default:
break;
}
break;
}
default:
return MakeEvalError() << "Unsupported DateTimestampPart "
<< DateTimestampPart_Name(part);
}
return absl::OkStatus();
}