41 static std::chrono::system_clock::time_point
from_sql_string(
const std::string& value) {
49 std::string clean_value = value;
50 std::chrono::microseconds fractional_seconds{0};
53 if (!clean_value.empty() && clean_value.front() ==
'\'' && clean_value.back() ==
'\'') {
54 clean_value = clean_value.substr(1, clean_value.length() - 2);
58 auto dot_pos = clean_value.find(
'.');
59 if (dot_pos != std::string::npos) {
60 auto end_pos = clean_value.find_first_of(
"Z+-", dot_pos);
61 if (end_pos == std::string::npos) {
62 end_pos = clean_value.length();
65 std::string frac_str = clean_value.substr(dot_pos + 1, end_pos - dot_pos - 1);
67 if (frac_str.length() > 6) {
68 frac_str = frac_str.substr(0, 6);
70 frac_str.append(6 - frac_str.length(),
'0');
73 fractional_seconds = std::chrono::microseconds{std::stoi(frac_str)};
74 clean_value.erase(dot_pos, end_pos - dot_pos);
75 if (end_pos < value.length()) {
76 clean_value += value.substr(end_pos);
81 std::chrono::minutes timezone_offset{0};
84 auto tz_pos = clean_value.find_last_of(
"Z");
85 if (tz_pos != std::string::npos && tz_pos == clean_value.length() - 1) {
87 clean_value = clean_value.substr(0, tz_pos);
90 tz_pos = clean_value.find_last_of(
"+-");
91 if (tz_pos != std::string::npos && tz_pos > 10) {
92 std::string tz_str = clean_value.substr(tz_pos);
93 clean_value = clean_value.substr(0, tz_pos);
96 bool is_positive = (tz_str[0] ==
'+');
97 std::string offset_str = tz_str.substr(1);
99 if (offset_str.empty()) {
100 throw std::invalid_argument(
"Empty timezone offset: " + tz_str);
103 int hours = 0, minutes = 0;
106 if (offset_str.find(
':') != std::string::npos) {
108 auto colon_pos = offset_str.find(
':');
109 if (offset_str.find(
':', colon_pos + 1) != std::string::npos) {
110 throw std::invalid_argument(
"Too many colons in timezone: " + tz_str);
112 hours = std::stoi(offset_str.substr(0, colon_pos));
113 auto minute_str = offset_str.substr(colon_pos + 1);
114 if (minute_str.empty()) {
115 throw std::invalid_argument(
"Missing minutes after colon: " + tz_str);
117 minutes = std::stoi(minute_str);
118 }
else if (offset_str.length() == 4) {
120 hours = std::stoi(offset_str.substr(0, 2));
121 minutes = std::stoi(offset_str.substr(2, 2));
122 }
else if (offset_str.length() == 2) {
124 hours = std::stoi(offset_str);
125 }
else if (offset_str.length() == 1) {
127 hours = std::stoi(offset_str);
129 throw std::invalid_argument(
"Invalid timezone format: " + tz_str);
131 }
catch (
const std::invalid_argument& e) {
132 throw std::invalid_argument(
"Invalid timezone format: " + tz_str);
133 }
catch (
const std::out_of_range& e) {
134 throw std::invalid_argument(
"Timezone values out of range: " + tz_str);
138 if (hours > 14 || hours < 0) {
139 throw std::invalid_argument(
"Invalid timezone hour offset (must be 0-14): " + tz_str);
141 if (minutes >= 60 || minutes < 0) {
142 throw std::invalid_argument(
"Invalid timezone minute offset (must be 0-59): " + tz_str);
146 int total_minutes = hours * 60 + minutes;
148 total_minutes = -total_minutes;
153 timezone_offset = std::chrono::minutes{total_minutes};
160 std::istringstream ss(clean_value);
165 if (clean_value.find(
'T') != std::string::npos) {
166 ss >> std::get_time(&tm,
"%Y-%m-%dT%H:%M:%S");
174 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
179 throw std::invalid_argument(
"Failed to parse timestamp: " + value);
190 std::time_t time_t_val;
194 time_t_val = _mkgmtime(&tm);
197#if defined(__GLIBC__) || defined(__APPLE__) || defined(__FreeBSD__)
198 time_t_val = timegm(&tm);
201 time_t_val = mktime(&tm);
202 if (time_t_val != -1) {
204 auto gmt_tm = *gmtime(&time_t_val);
205 auto local_tm = *localtime(&time_t_val);
208 auto gmt_time = mktime(&gmt_tm);
209 auto local_time = mktime(&local_tm);
210 auto offset = local_time - gmt_time;
211 time_t_val -= offset;
216 if (time_t_val == -1) {
217 throw std::invalid_argument(
"Invalid timestamp value: " + value);
220 auto time_point = std::chrono::system_clock::from_time_t(time_t_val);
224 auto utc_time_point = time_point - timezone_offset;
226 return utc_time_point + fractional_seconds;