static AdbcStatusCode ArrowTimestampToIsoString()

in c/driver/sqlite/statement_reader.c [152:247]


static AdbcStatusCode ArrowTimestampToIsoString(int64_t value, enum ArrowTimeUnit unit,
                                                char** buf, struct AdbcError* error) {
  int scale = 1;
  int strlen = 20;
  int rem = 0;

  switch (unit) {
    case NANOARROW_TIME_UNIT_SECOND:
      break;
    case NANOARROW_TIME_UNIT_MILLI:
      scale = 1000;
      strlen = 24;
      break;
    case NANOARROW_TIME_UNIT_MICRO:
      scale = 1000000;
      strlen = 27;
      break;
    case NANOARROW_TIME_UNIT_NANO:
      scale = 1000000000;
      strlen = 30;
      break;
  }

  rem = value % scale;
  if (rem < 0) {
    value -= scale;
    rem = scale + rem;
  }

  const int64_t seconds = value / scale;

#if SIZEOF_TIME_T < 8
  if ((seconds > INT32_MAX) || (seconds < INT32_MIN)) {
    SetError(error, "Timestamp %" PRId64 " with unit %d exceeds platform time_t bounds",
             value, unit);

    return ADBC_STATUS_INVALID_ARGUMENT;
  }
  const time_t time = (time_t)seconds;
#else
  const time_t time = seconds;
#endif

  struct tm broken_down_time;

#if defined(_WIN32)
  if (gmtime_s(&broken_down_time, &time) != 0) {
    SetError(error,
             "Could not convert timestamp %" PRId64 " with unit %d to broken down time",
             value, unit);

    return ADBC_STATUS_INVALID_ARGUMENT;
  }
#else
  if (gmtime_r(&time, &broken_down_time) != &broken_down_time) {
    SetError(error,
             "Could not convert timestamp %" PRId64 " with unit %d to broken down time",
             value, unit);

    return ADBC_STATUS_INVALID_ARGUMENT;
  }
#endif

  char* tsstr = malloc(strlen + 1);
  if (tsstr == NULL) {
    return ADBC_STATUS_IO;
  }

  if (strftime(tsstr, strlen, "%Y-%m-%dT%H:%M:%S", &broken_down_time) == 0) {
    SetError(error, "Call to strftime for timestamp %" PRId64 " with unit %d failed",
             value, unit);
    free(tsstr);
    return ADBC_STATUS_INVALID_ARGUMENT;
  }

  assert(rem >= 0);
  switch (unit) {
    case NANOARROW_TIME_UNIT_SECOND:
      break;
    case NANOARROW_TIME_UNIT_MILLI:
      tsstr[19] = '.';
      snprintf(tsstr + 20, strlen - 20, "%03d", rem % 1000u);
      break;
    case NANOARROW_TIME_UNIT_MICRO:
      tsstr[19] = '.';
      snprintf(tsstr + 20, strlen - 20, "%06d", rem % 1000000u);
      break;
    case NANOARROW_TIME_UNIT_NANO:
      tsstr[19] = '.';
      snprintf(tsstr + 20, strlen - 20, "%09d", rem % 1000000000u);
      break;
  }

  *buf = tsstr;
  return ADBC_STATUS_OK;
}