in sql_utils/public/functions/date_time_util.cc [1166:1269]
static absl::Status ExtractFromTimestampInternal(DateTimestampPart part,
absl::Time base_time,
absl::TimeZone timezone,
int32_t* output) {
const absl::TimeZone::CivilInfo info = timezone.At(base_time);
switch (part) {
case YEAR:
// Given contract of this method, year must be 'small'.
*output = static_cast<int32_t>(info.cs.year());
break;
case MONTH:
*output = info.cs.month();
break;
case DAY:
*output = info.cs.day();
break;
case DAYOFWEEK:
*output = internal_functions::DayOfWeekIntegerSunToSat1To7(
absl::GetWeekday(info.cs));
break;
case DAYOFYEAR:
*output = absl::GetYearDay(absl::CivilDay(info.cs));
break;
case QUARTER:
*output = (info.cs.month() - 1) / 3 + 1;
break;
case DATE: {
const int32_t date = CivilDayToEpochDays(absl::CivilDay(info.cs));
if (!IsValidDate(date)) {
// Error handling.
std::string time_str;
if (ConvertTimestampToString(base_time, kNanoseconds, timezone,
&time_str)
.ok()) {
return MakeEvalError()
<< "Invalid date extracted from timestamp " << time_str;
}
// Most likely should never happen.
return MakeEvalError() << "Invalid date extracted from timestamp "
<< absl::FormatTime(base_time, timezone);
}
*output = date;
break;
}
case WEEK: // _SUNDAY
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(info.cs.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);
const absl::CivilDay day(info.cs);
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 ISOYEAR:
// cast is safe, year "guaranteed" safe by method contract.
*output = static_cast<int32_t>(GetIsoYear(absl::CivilDay(info.cs)));
break;
case ISOWEEK: {
*output = GetIsoWeek(absl::CivilDay(info.cs));
break;
}
case HOUR:
*output = info.cs.hour();
break;
case MINUTE:
*output = info.cs.minute();
break;
case SECOND:
*output = info.cs.second();
break;
case MILLISECOND:
// cast is safe, guaranteed to be less than 1 thousand.
*output = static_cast<int32_t>(absl::ToInt64Milliseconds(info.subsecond));
break;
case MICROSECOND:
// cast is safe, guaranteed to be less than 1 million.
*output = static_cast<int32_t>(absl::ToInt64Microseconds(info.subsecond));
break;
case NANOSECOND:
// cast is safe, guaranteed to be less than 1 billion.
*output = static_cast<int32_t>(absl::ToInt64Nanoseconds(info.subsecond));
break;
default:
return MakeEvalError()
<< "Unexpected DateTimestampPart " << DateTimestampPart_Name(part);
}
return absl::OkStatus();
}