in sql_utils/public/functions/date_time_util.cc [3237:3325]
absl::Status DiffDatetimes(const DatetimeValue& datetime1,
const DatetimeValue& datetime2,
DateTimestampPart part, int64_t* output) {
if (!datetime1.IsValid()) {
return MakeEvalError() << "Invalid datetime value: "
<< datetime1.DebugString();
}
if (!datetime2.IsValid()) {
return MakeEvalError() << "Invalid datetime value: "
<< datetime2.DebugString();
}
switch (part) {
case YEAR:
*output = absl::CivilYear(datetime1.ConvertToCivilSecond()) -
absl::CivilYear(datetime2.ConvertToCivilSecond());
break;
case QUARTER: {
// This logic is the same as the one in DiffDates()
auto civil_time_1 = datetime1.ConvertToCivilSecond();
auto civil_time_2 = datetime2.ConvertToCivilSecond();
*output = (civil_time_1.year() * 12 + civil_time_1.month() - 1) / 3 -
(civil_time_2.year() * 12 + civil_time_2.month() - 1) / 3;
break;
}
case MONTH:
*output = absl::CivilMonth(datetime1.ConvertToCivilSecond()) -
absl::CivilMonth(datetime2.ConvertToCivilSecond());
break;
case WEEK:
case WEEK_MONDAY:
case WEEK_TUESDAY:
case WEEK_WEDNESDAY:
case WEEK_THURSDAY:
case WEEK_FRIDAY:
case WEEK_SATURDAY:
case ISOYEAR:
case ISOWEEK: {
int32_t date1;
int32_t date2;
int32_t int32_diff;
SQL_RETURN_IF_ERROR(ExtractFromDatetime(DATE, datetime1, &date1));
SQL_RETURN_IF_ERROR(ExtractFromDatetime(DATE, datetime2, &date2));
SQL_RETURN_IF_ERROR(DiffDates(date1, date2, part, &int32_diff));
*output = int32_diff;
break;
}
case DAY:
*output = absl::CivilDay(datetime1.ConvertToCivilSecond()) -
absl::CivilDay(datetime2.ConvertToCivilSecond());
break;
case HOUR:
case MINUTE:
case SECOND:
case MILLISECOND:
case MICROSECOND:
case NANOSECOND: {
auto DatetimeDiffOverflowErrorMaker = [&datetime1, &datetime2,
part]() -> absl::Status {
const std::string error_shared_prefix = absl::StrCat(
"DATETIME_DIFF at ", DateTimestampPart_Name(part),
" precision between datetime ", datetime1.DebugString(), " and ",
datetime2.DebugString());
if (part == NANOSECOND) {
return MakeEvalError() << error_shared_prefix << " causes overflow";
}
SQL_RET_CHECK_FAIL() << error_shared_prefix
<< " should never have overflow error";
};
return DiffWithPartsSmallerThanDay(
datetime1.ConvertToCivilSecond(), datetime1.Nanoseconds(),
datetime2.ConvertToCivilSecond(), datetime2.Nanoseconds(), part,
DatetimeDiffOverflowErrorMaker, output);
}
case DAYOFWEEK:
case DAYOFYEAR:
case DATE:
case DATETIME:
case TIME:
return MakeEvalError()
<< "Unsupported DateTimestampPart " << DateTimestampPart_Name(part)
<< " for DATETIME_DIFF";
default:
return MakeEvalError()
<< "Unexpected DateTimestampPart " << DateTimestampPart_Name(part)
<< " for DATETIME_DIFF";
}
return absl::OkStatus();
}