in be/src/exprs/udf-builtins.cc [283:385]
TimestampVal DoTrunc(
const TimestampValue& ts, TruncUnit trunc_unit, FunctionContext* ctx) {
const date& orig_date = ts.date();
const time_duration& orig_time = ts.time();
TimestampValue ret;
TimestampVal ret_val;
// check for invalid or malformed timestamps
switch (trunc_unit) {
case TruncUnit::MILLENNIUM:
// for millenium <= 2000 year value goes to 1001 (outside the supported range)
if (orig_date.is_special()) return TimestampVal::null();
if (orig_date.year() <= 2000) return TimestampVal::null();
break;
case TruncUnit::CENTURY:
// for century <= 1400 year value goes to 1301 (outside the supported range)
if (orig_date.is_special()) return TimestampVal::null();
if (orig_date.year() <= 1400) return TimestampVal::null();
break;
case TruncUnit::WEEK:
// anything less than 1400-1-6 we have to move to year 1399
if (orig_date.is_special()) return TimestampVal::null();
if (orig_date < date(1400, 1, 6)) return TimestampVal::null();
break;
case TruncUnit::YEAR:
case TruncUnit::QUARTER:
case TruncUnit::MONTH:
case TruncUnit::WW:
case TruncUnit::W:
case TruncUnit::DAY:
case TruncUnit::DAY_OF_WEEK:
case TruncUnit::DECADE:
if (orig_date.is_special()) return TimestampVal::null();
break;
case TruncUnit::HOUR:
case TruncUnit::MINUTE:
case TruncUnit::SECOND:
case TruncUnit::MILLISECONDS:
case TruncUnit::MICROSECONDS:
if (orig_time.is_special()) return TimestampVal::null();
break;
case TruncUnit::UNIT_INVALID:
DCHECK(false);
}
switch(trunc_unit) {
case TruncUnit::YEAR:
ret = TruncYear(orig_date);
break;
case TruncUnit::QUARTER:
ret = TruncQuarter(orig_date);
break;
case TruncUnit::MONTH:
ret = TruncMonth(orig_date);
break;
case TruncUnit::WW:
ret = TruncWW(orig_date);
break;
case TruncUnit::W:
ret = TruncW(orig_date);
break;
case TruncUnit::DAY:
ret = TruncDay(orig_date);
break;
case TruncUnit::DAY_OF_WEEK:
ret = TruncDayOfWeek(orig_date);
break;
case TruncUnit::HOUR:
ret = TruncHour(orig_date, orig_time);
break;
case TruncUnit::MINUTE:
ret = TruncMinute(orig_date, orig_time);
break;
case TruncUnit::MILLENNIUM:
ret = TruncMillennium(orig_date);
break;
case TruncUnit::CENTURY:
ret = TruncCentury(orig_date);
break;
case TruncUnit::DECADE:
ret = TruncDecade(orig_date);
break;
case TruncUnit::WEEK:
ret = TruncWeek(orig_date);
break;
case TruncUnit::SECOND:
ret = TruncSecond(orig_date, orig_time);
break;
case TruncUnit::MILLISECONDS:
ret = TruncMilliseconds(orig_date, orig_time);
break;
case TruncUnit::MICROSECONDS:
ret = TruncMicroseconds(orig_date, orig_time);
break;
default:
// internal error: implies StrToTruncUnit out of sync with this switch
ctx->SetError("truncate unit not supported");
return TimestampVal::null();
}
ret.ToTimestampVal(&ret_val);
return ret_val;
}