std::chrono::system_clock::time_point parseDateTime()

in squangle/mysql_client/Row.cpp [223:293]


std::chrono::system_clock::time_point parseDateTime(
    folly::StringPiece datetime,
    enum_field_types date_type) {
  const int TM_YEAR_BASE = 1900;

  // Clean struct and set daylight savings to information not available
  struct tm time_tm = {0};

  time_tm.tm_isdst = -1;
  std::string microseconds_str;
  int microseconds = 0;

  bool parse_succeeded = false;
  re2::StringPiece re2_datetime(datetime.data(), datetime.size());
  switch (date_type) {
    case MYSQL_TYPE_TIMESTAMP:
    case MYSQL_TYPE_DATETIME:
      static re2::RE2 timestamp_pattern(
          "(\\d{4})-(\\d{2})-(\\d{2}) "
          "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,6}))?");
      parse_succeeded = re2::RE2::FullMatch(
          re2_datetime,
          timestamp_pattern,
          &time_tm.tm_year,
          &time_tm.tm_mon,
          &time_tm.tm_mday,
          &time_tm.tm_hour,
          &time_tm.tm_min,
          &time_tm.tm_sec,
          &microseconds_str);
      break;
    case MYSQL_TYPE_DATE:
      static re2::RE2 date_pattern("(\\d{4})-(\\d{2})-(\\d{2})");
      parse_succeeded = re2::RE2::FullMatch(
          re2_datetime,
          date_pattern,
          &time_tm.tm_year,
          &time_tm.tm_mon,
          &time_tm.tm_mday);
      break;
    default:
      break;
  };

  if (!parse_succeeded) {
    throw std::range_error("Can't parse date");
  }
  if (!microseconds_str.empty()) {
    microseconds_str.resize(6, '0');
    microseconds = folly::to<int>(microseconds_str.c_str());
  }

  if (time_tm.tm_year) {
    time_tm.tm_year -= TM_YEAR_BASE;
  }

  if (time_tm.tm_mon) {
    time_tm.tm_mon -= 1;
  }

  auto t = mktime(&time_tm);

  if (t == -1) {
    throw std::range_error("Date values are invalid");
  }

  auto chrono_time = std::chrono::system_clock::from_time_t(t);

  chrono_time = chrono_time + std::chrono::microseconds(microseconds);
  return chrono_time;
}