absl::Status ConvertTimestampMicrosToStringWithTruncation()

in sql_utils/public/functions/date_time_util.cc [1823:1913]


absl::Status ConvertTimestampMicrosToStringWithTruncation(
    int64_t timestamp, absl::TimeZone timezone, std::string* out) {
  absl::Time time = absl::FromUnixMicros(timestamp);
  if (ABSL_PREDICT_FALSE(!IsValidTime(time))) {
    return MakeEvalError() << "Invalid timestamp value: " << timestamp;
  }
  absl::TimeZone normalized_timezone =
      internal_functions::GetNormalizedTimeZone(time, timezone);

  absl::TimeZone::CivilInfo info = normalized_timezone.At(time);

  // YYYY-mm-dd HH:MM:SS.ssssss+oo:oo
  // 01234567890123456789012345678901
  // 0         1         2         3
  // Maximum possible string size for the result.
  static constexpr size_t kFormatYMDHMSSize = 32;
  out->resize(kFormatYMDHMSSize);
  char* data = out->data();

  // YYYY-mm-dd HH:MM:SS.ssssss+oooo
  // 0123456789012345678901234567890
  // 0         1         2
  // Carefully put characters corresponding to different parts of formatted
  // string to the right positions.
  data[0] = info.cs.year() / 1000 + '0';
  data[1] = (info.cs.year() % 1000) / 100 + '0';
  data[2] = (info.cs.year() % 100) / 10 + '0';
  data[3] = info.cs.year() % 10 + '0';
  data[4] = '-';
  data[5] = info.cs.month() / 10 + '0';
  data[6] = info.cs.month() % 10 + '0';
  data[7] = '-';
  data[8] = info.cs.day() / 10 + '0';
  data[9] = info.cs.day() % 10 + '0';
  data[10] = ' ';
  data[11] = info.cs.hour() / 10 + '0';
  data[12] = info.cs.hour() % 10 + '0';
  data[13] = ':';
  data[14] = info.cs.minute() / 10 + '0';
  data[15] = info.cs.minute() % 10 + '0';
  data[16] = ':';
  data[17] = info.cs.second() / 10 + '0';
  data[18] = info.cs.second() % 10 + '0';

  // Deal with subsecond truncation to 0, 3 or 6 digits.
  size_t pos = 19;
  int64_t sub_seconds = timestamp % 1000000;
  if (sub_seconds < 0) {
    sub_seconds += 1000000;
  }
  if (sub_seconds > 0) {
    data[19] = '.';
    if (sub_seconds % 1000 > 0) {
      for (int i = 5; i >= 0; i--) {
        data[20 + i] = (sub_seconds % 10) + '0';
        sub_seconds /= 10;
      }
      pos += 7;
    } else {
      sub_seconds /= 1000;
      for (int i = 2; i >= 0; i--) {
        data[20 + i] = (sub_seconds % 10) + '0';
        sub_seconds /= 10;
      }
      pos += 4;
    }
  }

  bool positive_offset;
  int32_t hour_offset;
  int32_t minute_offset;
  internal_functions::GetSignHourAndMinuteTimeZoneOffset(
      info, &positive_offset, &hour_offset, &minute_offset);
  if (positive_offset) {
    data[pos++] = '+';
  } else {
    data[pos++] = '-';
  }
  // Write timezone offset using HH:mm format
  data[pos++] = hour_offset / 10 + '0';
  data[pos++] = hour_offset % 10 + '0';
  if (minute_offset > 0) {
    data[pos++] = ':';
    data[pos++] = minute_offset / 10 + '0';
    data[pos++] = minute_offset % 10 + '0';
  }
  // Initially we resized result for maximum possible size, here we set actual
  // size.
  out->resize(pos);
  return absl::OkStatus();
}