OmniSciDB  c1a53651b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DateTimeParser Class Reference

#include <DateTimeParser.h>

+ Collaboration diagram for DateTimeParser:

Classes

struct  DateTime
 

Public Types

enum  FormatType { FormatType::Date, FormatType::Time, FormatType::Timezone }
 

Public Member Functions

std::optional< int64_t > parse (std::string_view const, unsigned dim)
 
void setFormatType (FormatType)
 
std::string_view unparsed () const
 

Private Member Functions

bool parseWithFormat (std::string_view format, std::string_view &str)
 
void resetDateTime ()
 
bool updateDateTimeAndStr (char const field, std::string_view &)
 

Private Attributes

DateTime dt_
 
FormatType format_type_
 
std::string_view unparsed_
 

Detailed Description

Set format_type_ and parse date/time/timestamp strings into (s,ms,us,ns) since the epoch based on given dim in (0,3,6,9) respectively. Basic idea is to parse given string by matching to formats ("%Y-%m-%d", "%m/%d/%Y", ...) until a valid parse is found. Save parsed values into a DateTime dt_ struct from which the final epoch-based int64_t value is calculated.

Definition at line 55 of file DateTimeParser.h.

Member Enumeration Documentation

Enumerator
Date 
Time 
Timezone 

Definition at line 57 of file DateTimeParser.h.

57 { Date, Time, Timezone };

Member Function Documentation

std::optional< int64_t > DateTimeParser::parse ( std::string_view const  str,
unsigned  dim 
)

Definition at line 242 of file DateTimeParser.cpp.

References dt_, format_type_, anonymous_namespace{DateTimeParser.cpp}::formatViews(), DateTimeParser::DateTime::getTime(), parseWithFormat(), and unparsed_.

Referenced by dateTimeParseOptional< kDATE >(), dateTimeParseOptional< kTIME >(), and dateTimeParseOptional< kTIMESTAMP >().

242  {
243  static std::vector<std::vector<std::string_view>> const& format_views = formatViews();
244  auto const& formats = format_views.at(static_cast<int>(format_type_));
245  for (std::string_view const format : formats) {
246  std::string_view str_unparsed = str;
247  if (parseWithFormat(format, str_unparsed)) {
248  unparsed_ = str_unparsed;
249  return dt_.getTime(dim);
250  }
251  }
252  unparsed_ = str;
253  return std::nullopt;
254 }
std::string_view unparsed_
std::vector< std::vector< std::string_view > > formatViews()
bool parseWithFormat(std::string_view format, std::string_view &str)
int64_t getTime(unsigned const dim) const
FormatType format_type_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool DateTimeParser::parseWithFormat ( std::string_view  format,
std::string_view &  str 
)
private

Definition at line 217 of file DateTimeParser.cpp.

References anonymous_namespace{DateTimeParser.cpp}::eatSpace(), and updateDateTimeAndStr().

Referenced by parse().

217  {
218  while (!format.empty()) {
219  if (format.front() == '%') {
220  eatSpace(str);
221  if (!updateDateTimeAndStr(format[1], str)) {
222  return false;
223  }
224  format.remove_prefix(2);
225  } else if (isspace(format.front())) {
226  eatSpace(format);
227  eatSpace(str);
228  } else if (!str.empty() && format.front() == str.front()) {
229  format.remove_prefix(1);
230  str.remove_prefix(1);
231  } else {
232  return false;
233  }
234  }
235  return true;
236 }
bool updateDateTimeAndStr(char const field, std::string_view &)
void eatSpace(std::string_view &str)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void DateTimeParser::resetDateTime ( )
private

Definition at line 256 of file DateTimeParser.cpp.

References dt_.

Referenced by setFormatType().

256  {
257  dt_ = DateTime();
258 }

+ Here is the caller graph for this function:

void DateTimeParser::setFormatType ( FormatType  format_type)

Definition at line 260 of file DateTimeParser.cpp.

References format_type_, and resetDateTime().

Referenced by dateTimeParseOptional< kDATE >(), dateTimeParseOptional< kTIME >(), and dateTimeParseOptional< kTIMESTAMP >().

260  {
261  resetDateTime();
262  format_type_ = format_type;
263 }
FormatType format_type_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::string_view DateTimeParser::unparsed ( ) const

Definition at line 265 of file DateTimeParser.cpp.

References unparsed_.

Referenced by dateTimeParseOptional< kDATE >(), dateTimeParseOptional< kTIME >(), and dateTimeParseOptional< kTIMESTAMP >().

265  {
266  return unparsed_;
267 }
std::string_view unparsed_

+ Here is the caller graph for this function:

bool DateTimeParser::updateDateTimeAndStr ( char const  field,
std::string_view &  str 
)
private

Definition at line 271 of file DateTimeParser.cpp.

References cat(), DateTimeParser::DateTime::d, dt_, anonymous_namespace{DateTimeParser.cpp}::eatMonth(), DateTimeParser::DateTime::H, DateTimeParser::DateTime::m, DateTimeParser::DateTime::M, anonymous_namespace{DateTimeParser.cpp}::month_prefixes, DateTimeParser::DateTime::n, DateTimeParser::DateTime::p, anonymous_namespace{DateTimeParser.cpp}::pow_10, DateTimeParser::DateTime::S, DateTimeParser::DateTime::Y, and DateTimeParser::DateTime::z.

Referenced by parseWithFormat().

271  {
272  switch (field) {
273  case 'Y':
274  if (auto const year = fromChars<int64_t>(str)) {
275  dt_.Y = *year;
276  return true;
277  }
278  return false;
279  case 'y':
280  // %y matches 1 or 2 digits. If 3 or more digits are provided,
281  // then it is considered an unsuccessful parse.
282  if (auto const year = fromChars<unsigned>(str)) {
283  if (*year < 69) {
284  dt_.Y = 2000 + *year;
285  return true;
286  } else if (*year < 100) {
287  dt_.Y = 1900 + *year;
288  return true;
289  }
290  }
291  return false;
292  case 'm':
293  if (auto const month = fromChars<unsigned>(str, 2)) {
294  if (1 <= *month && *month <= 12) {
295  dt_.m = *month;
296  return true;
297  }
298  }
299  return false;
300  case 'b':
301  if (3 <= str.size()) {
302  int const key =
303  std::tolower(str[0]) << 16 | std::tolower(str[1]) << 8 | std::tolower(str[2]);
304  constexpr auto end = month_prefixes.data() + month_prefixes.size();
305  // This is faster than a lookup into a std::unordered_map.
306  auto const ptr = std::find(month_prefixes.data(), end, key);
307  if (ptr != end) {
308  dt_.m = ptr - month_prefixes.data() + 1;
309  eatMonth(dt_.m, str);
310  return true;
311  }
312  }
313  return false;
314  case 'd':
315  if (auto const day = fromChars<unsigned>(str, 2)) {
316  if (1 <= *day && *day <= 31) {
317  dt_.d = *day;
318  return true;
319  }
320  }
321  return false;
322  case 'H':
323  if (auto const hour = fromChars<unsigned>(str, 2)) {
324  if (*hour <= 23) {
325  dt_.H = *hour;
326  return true;
327  }
328  }
329  return false;
330  case 'I':
331  if (auto const hour = fromChars<unsigned>(str, 2)) {
332  if (1 <= *hour && *hour <= 12) {
333  dt_.H = *hour;
334  return true;
335  }
336  }
337  return false;
338  case 'M':
339  if (auto const minute = fromChars<unsigned>(str, 2)) {
340  if (*minute <= 59) {
341  dt_.M = *minute;
342  return true;
343  }
344  }
345  return false;
346  case 'S':
347  if (auto const second = fromChars<unsigned>(str, 2)) {
348  if (*second <= 61) {
349  dt_.S = *second;
350  if (!str.empty() && str.front() == '.') {
351  str.remove_prefix(1);
352  size_t len = str.size();
353  if (auto const ns = fromChars<unsigned>(str, 9)) {
354  len -= str.size();
355  dt_.n = *ns * pow_10[9 - len];
356  } else {
357  return false; // Reject period not followed by a digit
358  }
359  }
360  return true;
361  }
362  }
363  return false;
364  case 'z':
365  // [-+]\d\d:?\d\d
366  if (5 <= str.size() && (str.front() == '-' || str.front() == '+') &&
367  isdigit(str[1]) && isdigit(str[2]) && isdigit(str[4]) &&
368  (str[3] == ':' ? 6 <= str.size() && isdigit(str[5]) : isdigit(str[3]))) {
369  char const* sep = &str[3];
370  int hours{0}, minutes{0};
371  std::from_chars(str.data() + 1, sep, hours);
372  sep += *sep == ':';
373  std::from_chars(sep, sep + 2, minutes);
374  dt_.z = (str.front() == '-' ? -60 : 60) * (60 * hours + minutes);
375  str.remove_prefix(sep - str.data() + 2);
376  return true;
377  }
378  return false;
379  case 'p':
380  // %p implies optional, so never return false
381  if (boost::algorithm::istarts_with(str, "am") ||
382  boost::algorithm::istarts_with(str, "pm") ||
383  boost::algorithm::istarts_with(str, "a.m.") ||
384  boost::algorithm::istarts_with(str, "p.m.")) {
385  dt_.p = std::tolower(str.front()) == 'p';
386  str.remove_prefix(std::tolower(str[1]) == 'm' ? 2 : 4);
387  } else {
388  dt_.p.reset();
389  }
390  return true;
391  default:
392  throw std::runtime_error(cat("Unrecognized format: %", field));
393  }
394 }
std::optional< bool > p
std::string cat(Ts &&...args)
void eatMonth(unsigned const month, std::string_view &str)
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
Definition: JsonAccessors.h:31
constexpr std::array< int, 12 > month_prefixes

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Member Data Documentation

DateTime DateTimeParser::dt_
private

Definition at line 78 of file DateTimeParser.h.

Referenced by parse(), resetDateTime(), and updateDateTimeAndStr().

FormatType DateTimeParser::format_type_
private

Definition at line 79 of file DateTimeParser.h.

Referenced by parse(), and setFormatType().

std::string_view DateTimeParser::unparsed_
private

Definition at line 80 of file DateTimeParser.h.

Referenced by parse(), and unparsed().


The documentation for this class was generated from the following files: