Skip to content

Commit ad11986

Browse files
authored
Add timezone offset parsing and handle Clang compatibility for charconv (#6)
* Refactor parsing functions to return std::error_code and simplify error handling; update tests for ISO 8601 parsing. * Refactor parsing functions to improve readability and maintainability; add free parsing functions for year, month, day, hour, minute, second, and fraction. * Add timezone offset parsing and handle Clang compatibility for charconv
1 parent 41e2f24 commit ad11986

File tree

4 files changed

+59
-52
lines changed

4 files changed

+59
-52
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
parse date and times with {fmt} style into`std::chrono::time_point` {WIP}
44

5-
## [Usage](https://godbolt.org/z/nb3qdMYza)
5+
## [Usage](https://godbolt.org/z/PE3s1Y35d)
66

77
```C++
88
#include "mgutility/chrono/parse.hpp"

include/mgutility/_common/definitions.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,15 @@ SOFTWARE.
8282
#define MGUTILITY_CNSTEVL
8383
#endif
8484

85+
/**
86+
* @brief Detects if the compiler is Clang and its version is less than 7.
87+
*
88+
* If the compiler is Clang and its major version is less than 7,
89+
* CLANG_NO_CHARCONV is defined. This is used to indicate that the
90+
* <charconv> header is not fully supported in these versions of Clang.
91+
*/
92+
#if defined(__clang__) && __clang_major__ < 7
93+
#define CLANG_NO_CHARCONV
94+
#endif
95+
8596
#endif // MGUTILITY_COMMON_DEFINITIONS_HPP

include/mgutility/chrono/parse.hpp

Lines changed: 45 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,48 @@ MGUTILITY_CNSTXPR auto parse_fraction(detail::tm &result, string_view date_str,
250250
return error;
251251
}
252252

253+
MGUTILITY_CNSTXPR auto parse_timezone_offset(detail::tm &result, string_view date_str,
254+
uint32_t &next) -> std::errc {
255+
std::errc error{};
256+
if (--next < date_str.size() && date_str[next] == 'Z') {
257+
handle_timezone(result, 0);
258+
return error;
259+
}
260+
261+
if (next >= date_str.size() || (date_str[next] != '+' && date_str[next] != '-')) {
262+
return std::errc::invalid_argument;
263+
}
264+
265+
char sign = date_str[next++];
266+
int32_t hour = 0, minute = 0;
267+
268+
// Parse hour part (2 digits)
269+
error = parse_integer(hour, date_str, 2, next);
270+
if (error != std::errc{}) {
271+
return error;
272+
}
273+
274+
// Optional colon
275+
if (next < date_str.size() && date_str[next] == ':') {
276+
++next;
277+
}
278+
279+
// Parse minute part (2 digits)
280+
error = parse_integer(minute, date_str, 2, next);
281+
if (error != std::errc{}) {
282+
return error;
283+
}
284+
285+
int32_t offset = hour * 100 + minute;
286+
error = check_range(offset, 0, 1200);
287+
if (error != std::errc{}) {
288+
return error;
289+
}
290+
291+
handle_timezone(result, sign == '+' ? -offset : offset);
292+
return error;
293+
}
294+
253295
/**
254296
* @brief Parses a date and time string according to a specified format.
255297
*
@@ -367,55 +409,9 @@ MGUTILITY_CNSTXPR auto get_time(detail::tm &result, string_view format,
367409
}
368410
break;
369411
case 'z': { // Timezone offset (+/-HHMM)
370-
if (*(date_str.begin() + next - 1) != 'Z') {
371-
char sign{};
372-
auto diff{0};
373-
for (auto j{next - 1}; j < date_str.size(); ++j) {
374-
if (date_str[j] == '-' || date_str[j] == '+') {
375-
sign = date_str[j];
376-
diff = j - next + 1;
377-
break;
378-
}
379-
}
380-
auto hour_offset_str =
381-
string_view{date_str.data() + next + diff, date_str.size() - 1};
382-
auto pos = hour_offset_str.find(':');
383-
auto offset{0};
384-
if (pos < 3 && pos > 0) {
385-
next = 0;
386-
int32_t hour_offset{0};
387-
int32_t min_offset{0};
388-
error = parse_integer(hour_offset, hour_offset_str, 2, next);
389-
if (error != std::errc{}) {
390-
return error;
391-
}
392-
error = parse_integer(min_offset, hour_offset_str, 2, next);
393-
if (error != std::errc{}) {
394-
return error;
395-
}
396-
offset = hour_offset * 100 + min_offset;
397-
} else {
398-
if (date_str.size() - next > 4 + diff) {
399-
return std::errc::invalid_argument;
400-
}
401-
error = parse_integer(offset, date_str, date_str.size() - next,
402-
next, diff);
403-
if (error != std::errc{}) {
404-
return error;
405-
}
406-
}
407-
error = check_range(offset, 0, 1200);
408-
if (error != std::errc{}) {
409-
return error;
410-
}
411-
switch (sign) {
412-
case '+':
413-
handle_timezone(result, offset * -1);
414-
break;
415-
case '-':
416-
handle_timezone(result, offset);
417-
break;
418-
}
412+
error = parse_timezone_offset(result, date_str, next);
413+
if (error != std::errc{}) {
414+
return error;
419415
}
420416
} break;
421417
default:

include/mgutility/std/charconv.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ SOFTWARE.
2626
#include "mgutility/_common/definitions.hpp"
2727
#include <system_error>
2828

29-
#if MGUTILITY_CPLUSPLUS >= 201703L
29+
#if MGUTILITY_CPLUSPLUS >= 201703L && !defined(CLANG_NO_CHARCONV)
3030
#include <charconv>
3131
#endif
3232

3333
namespace mgutility {
3434

35-
#if MGUTILITY_CPLUSPLUS < 201703L
35+
#if MGUTILITY_CPLUSPLUS < 201703L || defined(CLANG_NO_CHARCONV)
3636

3737
/**
3838
* @brief Result structure for from_chars function.

0 commit comments

Comments
 (0)