20 #include <boost/algorithm/string/predicate.hpp>
32 constexpr std::array<int, 12>
month_prefixes{{int(
'j') << 16 | int(
'a') << 8 | int(
'n'),
33 int(
'f') << 16 | int(
'e') << 8 | int(
'b'),
34 int(
'm') << 16 | int(
'a') << 8 | int(
'r'),
35 int(
'a') << 16 | int(
'p') << 8 | int(
'r'),
36 int(
'm') << 16 | int(
'a') << 8 | int(
'y'),
37 int(
'j') << 16 | int(
'u') << 8 | int(
'n'),
38 int(
'j') << 16 | int(
'u') << 8 | int(
'l'),
39 int(
'a') << 16 | int(
'u') << 8 | int(
'g'),
40 int(
's') << 16 | int(
'e') << 8 | int(
'p'),
41 int(
'o') << 16 | int(
'c') << 8 | int(
't'),
42 int(
'n') << 16 | int(
'o') << 8 | int(
'v'),
43 int(
'd') << 16 | int(
'e') << 8 | int(
'c')}};
61 pow_10[10]{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
67 int64_t
const era = (y < 0 ? y - 399 : y) / 400;
68 unsigned const yoe =
static_cast<unsigned>(y - era * 400);
69 unsigned const doy = (153 * (m + (m <= 2 ? 9 : -3)) + 2) / 5 + d - 1;
70 unsigned const doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
71 return era * 146097 +
static_cast<int64_t
>(doe) - 719468;
76 return {{{
"%Y-%m-%d",
"%m/%d/%y",
"%m/%d/%Y",
"%Y/%m/%d",
"%d-%b-%y",
"%d/%b/%Y"},
88 void eatMonth(
unsigned const month, std::string_view& str) {
91 if (boost::algorithm::istarts_with(str, suffix)) {
92 str.remove_prefix(suffix.size());
97 while (!str.empty() && isspace(str.front())) {
105 template <
typename T>
107 size_t maxlen = std::numeric_limits<size_t>::max()) {
109 maxlen = std::min(maxlen, str.size());
110 auto const result = std::from_chars(str.data(), str.data() + maxlen, retval);
111 if (result.ec == std::errc()) {
112 str.remove_prefix(result.ptr - str.data());
119 std::optional<int64_t>
unixTime(std::string_view
const str) {
121 auto const result = std::from_chars(str.data(), str.data() + str.size(), time);
123 bool const is_valid =
result.ec == std::errc() &&
124 (
result.ptr == str.data() + str.size() ||
126 std::all_of(
result.ptr + 1, str.data() + str.size(), isdigit)));
127 return is_valid ? std::make_optional(time) : std::nullopt;
136 unsigned const dim) {
137 if (!str.empty() && str.front() ==
'T') {
138 str.remove_prefix(1);
142 std::optional<int64_t> time = parser.
parse(str, dim);
147 std::string_view timezone = parser.
unparsed();
149 std::optional<int64_t> tz = parser.
parse(timezone, dim);
153 return *time + tz.value_or(0);
160 unsigned const dim) {
161 if (!str.empty() && str.front() ==
'T') {
162 str.remove_prefix(1);
167 std::optional<int64_t> date = parser.
parse(str, dim);
172 std::string_view time_of_day = parser.
unparsed();
173 if (time_of_day.empty()) {
175 }
else if (time_of_day.front() ==
'T' || time_of_day.front() ==
':') {
176 time_of_day.remove_prefix(1);
179 std::optional<int64_t> time = parser.
parse(time_of_day, dim);
181 std::string_view timezone = parser.
unparsed();
183 std::optional<int64_t> tz = parser.
parse(timezone, dim);
184 return *date + time.value_or(0) + tz.value_or(0);
191 unsigned const dim) {
195 std::optional<int64_t> date = parser.
parse(str, dim);
200 std::string_view timezone = parser.
unparsed();
202 std::optional<int64_t> tz = parser.
parse(timezone, dim);
203 return *date + tz.value_or(0);
209 int const seconds =
static_cast<int>(3600 *
H + 60 *
M +
S) -
z +
210 (
p ? *
p &&
H != 12 ? 12 * 3600
211 : !*
p &&
H == 12 ? -12 * 3600
214 return (24 * 3600 * days + seconds) *
pow_10[dim] +
n /
pow_10[9 - dim];
220 while (!format.empty()) {
221 if (format.front() ==
'%') {
226 format.remove_prefix(2);
227 }
else if (isspace(format.front())) {
230 }
else if (!str.empty() && format.front() == str.front()) {
231 format.remove_prefix(1);
232 str.remove_prefix(1);
245 static std::vector<std::vector<std::string_view>>
const& format_views =
formatViews();
246 auto const& formats = format_views.at(static_cast<int>(
format_type_));
247 for (std::string_view
const format : formats) {
248 std::string_view str_unparsed = str;
276 if (
auto const year = fromChars<int64_t>(str)) {
284 if (
auto const year = fromChars<unsigned>(str)) {
286 dt_.
Y = 2000 + *year;
288 }
else if (*year < 100) {
289 dt_.
Y = 1900 + *year;
295 if (
auto const month = fromChars<unsigned>(str, 2)) {
296 if (1 <= *month && *month <= 12) {
303 if (3 <= str.size()) {
305 std::tolower(str[0]) << 16 | std::tolower(str[1]) << 8 | std::tolower(str[2]);
317 if (
auto const day = fromChars<unsigned>(str, 2)) {
318 if (1 <= *day && *day <= 31) {
325 if (
auto const hour = fromChars<unsigned>(str, 2)) {
333 if (
auto const hour = fromChars<unsigned>(str, 2)) {
334 if (1 <= *hour && *hour <= 12) {
341 if (
auto const minute = fromChars<unsigned>(str, 2)) {
349 if (
auto const second = fromChars<unsigned>(str, 2)) {
352 if (!str.empty() && str.front() ==
'.') {
353 str.remove_prefix(1);
354 size_t len = str.size();
355 if (
auto const ns = fromChars<unsigned>(str, 9)) {
368 if (5 <= str.size() && (str.front() ==
'-' || str.front() ==
'+') &&
369 isdigit(str[1]) && isdigit(str[2]) && isdigit(str[4]) &&
370 (str[3] ==
':' ? 6 <= str.size() && isdigit(str[5]) : isdigit(str[3]))) {
371 char const* sep = &str[3];
372 int hours{0}, minutes{0};
373 std::from_chars(str.data() + 1, sep, hours);
375 std::from_chars(sep, sep + 2, minutes);
376 dt_.
z = (str.front() ==
'-' ? -60 : 60) * (60 * hours + minutes);
377 str.remove_prefix(sep - str.data() + 2);
383 if (boost::algorithm::istarts_with(str,
"am") ||
384 boost::algorithm::istarts_with(str,
"pm") ||
385 boost::algorithm::istarts_with(str,
"a.m.") ||
386 boost::algorithm::istarts_with(str,
"p.m.")) {
387 dt_.
p = std::tolower(str.front()) ==
'p';
388 str.remove_prefix(std::tolower(str[1]) ==
'm' ? 2 : 4);
394 throw std::runtime_error(
cat(
"Unrecognized format: %", field));
399 return out << dt.
Y <<
'-' << dt.
m <<
'-' << dt.
d <<
' ' << dt.
H <<
':' << dt.
M <<
':'
400 << dt.
S <<
'.' << dt.
n <<
" p("
401 << (dt.
p ? *dt.
p ?
"true" :
"false" :
"unset") <<
") z(" << dt.
z <<
')';
std::optional< int64_t > parse(std::string_view const, unsigned dim)
bool updateDateTimeAndStr(char const field, std::string_view &)
std::optional< int64_t > unixTime(std::string_view const str)
std::ostream & operator<<(std::ostream &os, const SessionInfo &session_info)
std::string_view unparsed_
std::vector< std::vector< std::string_view > > formatViews()
void eatMonth(unsigned const month, std::string_view &str)
bool parseWithFormat(std::string_view format, std::string_view &str)
void eatSpace(std::string_view &str)
std::string suffix(SQLTypes type)
constexpr unsigned pow_10[10]
std::optional< int64_t > dateTimeParseOptional< kTIME >(std::string_view str, unsigned const dim)
const rapidjson::Value & field(const rapidjson::Value &obj, const char field[]) noexcept
std::optional< T > fromChars(std::string_view &str, size_t maxlen=std::numeric_limits< size_t >::max())
std::optional< int64_t > dateTimeParseOptional< kDATE >(std::string_view str, unsigned const dim)
std::optional< int64_t > dateTimeParseOptional< kTIMESTAMP >(std::string_view str, unsigned const dim)
int64_t getTime(unsigned const dim) const
constexpr std::array< int, 12 > month_prefixes
constexpr std::array< std::string_view, 13 > month_suffixes
int64_t daysFromCivil(int64_t y, unsigned const m, unsigned const d)
void setFormatType(FormatType)
std::string_view unparsed() const