in sql_utils/public/functions/date_time_util.cc [774:853]
static bool AddAtLeastDaysToCivilTime(DateTimestampPart part, int32_t interval,
absl::CivilSecond cs, int subsecond,
absl::TimeZone timezone,
TimestampScale scale,
absl::Time* result_timestamp) {
switch (part) {
case YEAR: {
int year;
// cast is safe, given method contract.
if (!Add<int32_t>(static_cast<int32_t>(cs.year()), interval, &year,
kNoError)) {
return false;
}
int month = cs.month();
int day = cs.day();
AdjustYearMonthDay(&year, &month, &day);
if (!TimestampFromParts(year, month, day, cs.hour(), cs.minute(),
cs.second(), subsecond, scale, timezone,
result_timestamp)) {
return false;
}
break;
}
case QUARTER:
if (!Multiply<int32_t>(interval, 3, &interval, kNoError)) {
return false;
}
ABSL_FALLTHROUGH_INTENDED;
case MONTH: {
int32_t month;
if (!Add<int32_t>(cs.month(), interval, &month, kNoError)) {
return false;
}
int day = cs.day();
// cast is safe, given method contract.
int year = static_cast<int32_t>(cs.year());
AdjustYearMonthDay(&year, &month, &day);
if (!TimestampFromParts(year, month, day, cs.hour(), cs.minute(),
cs.second(), subsecond, scale, timezone,
result_timestamp)) {
return false;
}
break;
}
case WEEK:
if (!Multiply<int32_t>(interval, 7, &interval, kNoError)) {
return false;
}
ABSL_FALLTHROUGH_INTENDED;
case DAY: {
absl::CivilDay date;
// cast is safe, given method contract.
if (!MakeDate(static_cast<int32_t>(cs.year()), cs.month(), cs.day(),
&date)) {
// This is unreachable since the input timestamp is valid and
// therefore cannot be outside the Date range bounds.
return false;
}
// This could probably be simplified to avoid bouncing back and forth
// between civil day, but its not clear how important it is to preserve
// exact overflow semantics, or how that would interact with
// absl::CivilDay (which encodes days simply as 'int').
int days = CivilDayToEpochDays(date);
if (!Add<int32_t>(days, interval, &days, kNoError)) {
return false;
}
date = EpochDaysToCivilDay(days);
if (!TimestampFromParts(date.year(), date.month(), date.day(), cs.hour(),
cs.minute(), cs.second(), subsecond, scale,
timezone, result_timestamp)) {
return false;
}
break;
}
default:
SQL_DCHECK(false) << "Should not reach here";
return false;
}
return true;
}