Skip to content

Parser for chrono::time_point#648

Open
ron0studios wants to merge 1 commit intogetml:mainfrom
ron0studios:main
Open

Parser for chrono::time_point#648
ron0studios wants to merge 1 commit intogetml:mainfrom
ron0studios:main

Conversation

@ron0studios
Copy link
Copy Markdown
Contributor

Addresses #586.

There are a couple immediate problems that I am not sure how to proceed with.

This forces an ISO 8601 time format conversion, which also needs some logic to convert. This could be slow.

I believe Parser duration uses a simpler struct format, which makes sense for the type:
{"seconds": 1234567, "microseconds": 123456}, but for a time_point a date-time format would make more sense.

Also we could go a step further and use nanosecond precision instead of the microsecond precision shown here.

TODO

  • timezone support? currently using Z (utc)
  • improve from_string performance
  • docs

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for std::chrono::time_point serialization and deserialization, including a new Parser_time_point.hpp header and comprehensive unit tests. The implementation handles ISO 8601 formatting with microsecond precision. Feedback focuses on restricting the parser to std::chrono::system_clock to ensure compatibility with calendar-time conversions, increasing precision to nanoseconds, and improving input validation to strictly enforce the 'Z' suffix. Additionally, a thread-safety improvement was suggested regarding locale handling during parsing.

Comment on lines +17 to +19
template <class R, class W, class Clock, class Duration, class ProcessorsType>
requires AreReaderAndWriter<R, W, std::chrono::time_point<Clock, Duration>>
struct Parser<R, W, std::chrono::time_point<Clock, Duration>, ProcessorsType> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation assumes the clock is std::chrono::system_clock by using from_time_t and to_time_t. However, the template specialization is currently open to any Clock. Clocks like std::chrono::steady_clock do not represent calendar time and cannot be portably converted to/from ISO 8601 strings using these methods. The specialization should be restricted to std::chrono::system_clock.

Suggested change
template <class R, class W, class Clock, class Duration, class ProcessorsType>
requires AreReaderAndWriter<R, W, std::chrono::time_point<Clock, Duration>>
struct Parser<R, W, std::chrono::time_point<Clock, Duration>, ProcessorsType> {
template <class R, class W, class Duration, class ProcessorsType>
requires AreReaderAndWriter<R, W, std::chrono::time_point<std::chrono::system_clock, Duration>>
struct Parser<R, W, std::chrono::time_point<std::chrono::system_clock, Duration>, ProcessorsType> {


using ParentType = Parent<W>;

using TimePointType = std::chrono::time_point<Clock, Duration>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Update the alias to reflect the restriction to system_clock.

Suggested change
using TimePointType = std::chrono::time_point<Clock, Duration>;
using TimePointType = std::chrono::time_point<std::chrono::system_clock, Duration>;

Comment on lines +46 to +47
const auto sys_time =
std::chrono::time_point_cast<std::chrono::microseconds>(_tp);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation is currently limited to microsecond precision. Since std::chrono::system_clock::time_point often supports nanosecond precision (especially on Linux), and the PR description mentions this as a goal, consider using std::chrono::nanoseconds here and in the parsing logic to avoid loss of data during serialization.

Comment on lines +113 to +115
}

return std::chrono::time_point_cast<Duration>(tp);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The parser should validate that the 'Z' suffix is present and that the entire input string has been consumed. Currently, it may silently ignore trailing characters or incorrect suffixes (e.g., it would successfully parse 2024-01-15T10:30:00Invalid).

      }

      if (*rest != 'Z' || *(rest + 1) != '\0') {
        return error("Could not parse time point from '" + _str + "'.");
      }

      return std::chrono::time_point_cast<Duration>(tp);

static const char* parse_datetime(const char* _str, std::tm* _tm) {
#if defined(_MSC_VER) || defined(__MINGW32__)
std::istringstream input(_str);
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using setlocale(LC_ALL, nullptr) is not thread-safe and depends on the global environment. For parsing a fixed machine-readable format like ISO 8601, std::locale::classic() is preferred as it ensures consistent behavior regardless of the user's system settings.

Suggested change
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
input.imbue(std::locale::classic());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant