in sql_utils/public/functions/date_time_util.cc [3665:3730]
static absl::Status AddTimeInternal(const TimeValue& time,
DateTimestampPart part, int64_t interval,
TimeValue* output) {
if (!time.IsValid()) {
return MakeEvalError() << "Invalid time value: " << time.DebugString();
}
if (!(part == HOUR || part == MINUTE || part == SECOND ||
part == MILLISECOND || part == MICROSECOND || part == NANOSECOND)) {
return MakeEvalError() << "Unsupported DateTimestampPart "
<< DateTimestampPart_Name(part);
}
int hour = time.Hour();
int minute = time.Minute();
int second = time.Second();
int nanoseconds = time.Nanoseconds();
while (interval != 0 && part != DAY) {
switch (part) {
case NANOSECOND:
AddOnField(interval, 1000000000, &nanoseconds, &interval);
part = SECOND;
break;
case MICROSECOND: {
int microseconds = 0;
int64_t carry_1;
AddOnField(interval, 1000000, µseconds, &carry_1);
int64_t carry_2;
AddOnField(microseconds * 1000, 1000000000, &nanoseconds, &carry_2);
interval = carry_1 + carry_2;
part = SECOND;
break;
}
case MILLISECOND: {
int millisecond = 0;
int64_t carry_1;
AddOnField(interval, 1000, &millisecond, &carry_1);
int64_t carry_2;
AddOnField(millisecond * 1000000, 1000000000, &nanoseconds, &carry_2);
interval = carry_1 + carry_2;
part = SECOND;
break;
}
case SECOND: {
AddOnField(interval, 60, &second, &interval);
part = MINUTE;
break;
}
case MINUTE: {
AddOnField(interval, 60, &minute, &interval);
part = HOUR;
break;
}
case HOUR: {
AddOnField(interval, 24, &hour, &interval);
part = DAY;
break;
}
default:
break;
}
}
*output = TimeValue::FromHMSAndNanos(hour, minute, second, nanoseconds);
// This check should never fail as all fields should be in range.
SQL_DCHECK(output->IsValid()) << output->DebugString();
return absl::OkStatus();
}