static absl::Status ExtractFromTimestampInternal()

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();
}