1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| #include <cstdint> #include <string> #include <vector> #include <regex> #include <time.h>
using time_regex_type = std::pair<std::string, std::regex>; using time_regex_vec_type = std::vector<time_regex_type>;
std::string supported_time_formats(const time_regex_vec_type &fmtlist) { std::string time_fmts; for (size_t i = 0; i < fmtlist.size(); i++) { time_fmts += fmtlist[i].first + "\n"; } return time_fmts; }
bool datetime::verify_time(const struct tm &time) { if (time.tm_year < 1900) { CUTL_ERROR("the year should be >= 1900"); return false; } if (time.tm_mon < 1 || time.tm_mon > 12) { CUTL_ERROR("the month should be between 1 and 12"); return false; } std::vector<int> large_month = {1, 3, 5, 7, 8, 10, 12}; if (std::find(large_month.begin(), large_month.end(), time.tm_mon) != large_month.end() && (time.tm_mday < 1 || time.tm_mday > 31)) { CUTL_ERROR("the day should be between 1 and 31 for " + std::to_string(time.tm_mon) + " month"); return false; } std::vector<int> small_month = {4, 6, 9, 11}; if (std::find(small_month.begin(), small_month.end(), time.tm_mon) != small_month.end() && (time.tm_mday < 1 || time.tm_mday > 30)) { CUTL_ERROR("the day should be between 1 and 30 for " + std::to_string(time.tm_mon) + " month"); return false; } if (time.tm_mon == 2) { auto is_leap_year = [](int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); }; if (is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 29)) { CUTL_ERROR("the day should be between 1 and 29 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2)); return false; } if (!is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 28)) { CUTL_ERROR("the day should be between 1 and 28 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2)); return false; } }
if (time.tm_hour < 0 || time.tm_hour > 23) { CUTL_ERROR("the hour should be between 0 and 23"); return false; } if (time.tm_min < 0 || time.tm_min > 59) { CUTL_ERROR("the minute should be between 0 and 59"); return false; } if (time.tm_sec < 0 || time.tm_sec > 59) { CUTL_ERROR("the second should be between 0 and 59"); return false; }
return true; }
uint64_t parse_datetime(const std::string &time_text, int isdst) { std::smatch matchRes; bool result = false; static time_regex_vec_type fmt_list = { std::make_pair("YYYY-MM-DD HH:MM:SS.sss", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")), std::make_pair("YYYY-MM-DD HH:MM:SS", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")), std::make_pair("YYYY.MM.DD HH:MM:SS.sss", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")), std::make_pair("YYYY.MM.DD HH:MM:SS", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")), std::make_pair("YYYY/MM/DD HH:MM:SS.sss", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")), std::make_pair("YYYY/MM/DD HH:MM:SS", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")), std::make_pair("YYYYMMDD HH:MM:SS.sss", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")), std::make_pair("YYYYMMDD HH:MM:SS", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")), }; for (size_t i = 0; i < fmt_list.size(); i++) { auto &fmt_text = fmt_list[i].first; auto &fmt_pattern = fmt_list[i].second; result = std::regex_search(time_text, matchRes, fmt_pattern); if (result) { CUTL_DEBUG("matched regex: " + fmt_text); break; } }
if (!result || matchRes.size() < 7) { auto time_fmts = supported_time_formats(fmt_list); CUTL_ERROR("Only the following time formats are supported:\n" + time_fmts); return 0; }
CUTL_DEBUG("matchRes size:" + std::to_string(matchRes.size()) + ", res:" + matchRes[0].str()); int ms = 0; if (matchRes.size() == 8) { ms = std::stoi(matchRes[7].str()); } struct tm time = {}; if (matchRes.size() >= 7) { for (size_t i = 1; i < 7; i++) { time.tm_year = std::stoi(matchRes[1]); time.tm_mon = std::stoi(matchRes[2]); time.tm_mday = std::stoi(matchRes[3]); time.tm_hour = std::stoi(matchRes[4]); time.tm_min = std::stoi(matchRes[5]); time.tm_sec = std::stoi(matchRes[6]); time.tm_isdst = isdst; } } if (!verify_time(time)) { return 0; }
time.tm_year -= 1900; time.tm_mon -= 1; auto ret = mktime(&time); if (ret == -1) { CUTL_ERROR("mktime() failed"); return 0; } auto s = static_cast<uint64_t>(ret); return s; }
|