in sql_utils/public/functions/parse_date_time.cc [792:858]
static absl::Status ComputeYearMonthDayFromISOParts(
int64_t* year, int* month, int* mday, DateParseContext* date_parse_context) {
std::optional<ParseElementInfo> iso_year_info;
std::optional<ParseElementInfo> iso_week_info;
std::optional<ParseElementInfo> weekday_info;
std::optional<ParseElementInfo> iso_dayofyear_info;
for (const auto& element : date_parse_context->elements) {
switch (element.fmt) {
case 'A': // Full weekday name
case 'a': // Abbreviated weekday name
case 'u': // weekday number 1-7, starting Monday
case 'w': // weekday number 0-6, starting Sunday
weekday_info = element;
break;
case 'G': // ISO 8601 year with century, e.g., 2019
case 'g': // ISO 8601 year without century, e.g., 19
iso_year_info = element;
break;
case 'J': // ISO day of year
iso_dayofyear_info = element;
break;
case 'V': // ISO 8601 week number of the ISO YEAR
iso_week_info = element;
break;
default:
SQL_RET_CHECK_FAIL() << "Unexpected format element: '" << element.fmt
<< "'";
}
}
// The canonicalized date parse context should ensure that only one of
// week or day of year is set, so we validate that here.
SQL_RET_CHECK(!iso_week_info.has_value() || !iso_dayofyear_info.has_value());
absl::CivilDay civil_day;
SQL_RET_CHECK(iso_year_info.has_value());
// Valid combinations are:
// 1) ISO week - interpreted as the first day of this ISO week
// 2) ISO week and day of week
// 4) ISO day of year
// 3) ISO year only - interpreted as the first day of the ISO year
if (iso_week_info.has_value()) {
SQL_RET_CHECK(!iso_dayofyear_info.has_value());
// Covers year/week, and year/week/weekday.
SQL_RETURN_IF_ERROR(ComputeDateFromISOYearWeekAndWeekday(
iso_year_info.value(), iso_week_info.value(), weekday_info,
&civil_day));
} else {
// Covers year, and year/dayofyear.
SQL_RET_CHECK(!iso_week_info.has_value());
SQL_RET_CHECK(!weekday_info.has_value());
// Compute date from ISO year and day of year (optional).
SQL_RETURN_IF_ERROR(ComputeDateFromISOYearAndDayOfYear(
iso_year_info.value(), iso_dayofyear_info, &civil_day));
}
*year = civil_day.year();
*month = civil_day.month();
*mday = civil_day.day();
// Verify that the result date is valid.
if (!IsValidDay(*year, *month, *mday)) {
return MakeEvalError()
<< "Out-of-range datetime field in parsing function; year: " << *year
<< ", month: " << *month << ", day: " << *mday;
}
return absl::OkStatus();
}