in sql_utils/public/functions/date_time_util.cc [2535:2605]
absl::Status ExtractFromDate(DateTimestampPart part, int32_t date,
int32_t* output) {
if (!IsValidDate(date)) {
return MakeEvalError() << "Invalid date value: " << date;
}
absl::CivilDay day = EpochDaysToCivilDay(date);
switch (part) {
case YEAR:
// Year for valid dates fits into int32_t
*output = static_cast<int32_t>(day.year());
break;
case QUARTER:
*output = (day.month() - 1) / 3 + 1;
break;
case MONTH:
*output = day.month();
break;
case DAY:
*output = day.day();
break;
case ISOYEAR:
// Year for valid dates fits into int32_t
*output = static_cast<int32_t>(GetIsoYear(day));
break;
case WEEK:
case WEEK_MONDAY:
case WEEK_TUESDAY:
case WEEK_WEDNESDAY:
case WEEK_THURSDAY:
case WEEK_FRIDAY:
case WEEK_SATURDAY: {
const absl::CivilDay first_calendar_day_of_year(day.year(), 1, 1);
SQL_ASSIGN_OR_RETURN(const absl::Weekday weekday,
GetFirstWeekDayOfWeek(part));
const absl::CivilDay effective_first_day_of_year =
NextWeekdayOrToday(first_calendar_day_of_year, weekday);
if (day < effective_first_day_of_year) {
*output = 0;
} else {
// cast is safe, guaranteed to be less than 52.
*output =
static_cast<int32_t>(((day - effective_first_day_of_year) / 7) + 1);
}
break;
}
case ISOWEEK:
*output = GetIsoWeek(day);
break;
case DAYOFWEEK:
*output = internal_functions::DayOfWeekIntegerSunToSat1To7(
absl::GetWeekday(day));
break;
case DAYOFYEAR:
*output = absl::GetYearDay(day);
break;
case DATE:
case HOUR:
case MINUTE:
case SECOND:
case MILLISECOND:
case MICROSECOND:
case NANOSECOND:
return MakeEvalError()
<< "Unsupported DateTimestampPart " << DateTimestampPart_Name(part)
<< " to extract from date";
default:
return MakeEvalError()
<< "Unexpected DateTimestampPart " << DateTimestampPart_Name(part);
}
return absl::OkStatus();
}