Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date Parse: one pattern for ISO8601 DATE or DATE TIME #803

Open
shawncao opened this issue Sep 21, 2023 · 6 comments
Open

Date Parse: one pattern for ISO8601 DATE or DATE TIME #803

shawncao opened this issue Sep 21, 2023 · 6 comments

Comments

@shawncao
Copy link

I'm wondering if there is a flexible way to write the pattern so that it can parse either DATE or DATE-TIME (ISO8601)

for example, I have mixed values from a set:

  • 2021-11-02
  • 2021-11-23T20:55:92Z

I hope we can do

value >> date::parse("%FT%T", timepoint)

Obviously "%FT%T" will translate "2021-11-02" into value 0

Any ideas?

@shawncao
Copy link
Author

this is my hack to work around this issue, not ideal:

  static int64_t time(const std::string_view datetime, const std::string& pattern) {
    // introduce a special tag to handle iso8601 flexible values: DATE or DATETIME
    // for example 2021-11-02, 2021-11-02T12:00:00Z, 2021-11-02T12:00:00.123Z
    auto p = pattern;
    if (pattern == "iso8601") {
      if (datetime.size() == 10) {
        p = "%F";
      } else {
        p = "%FT%TZ";
      }
    }

    date::sys_time<std::chrono::microseconds> tp;
    std::istringstream value(datetime.data());
    value >> date::parse(p, tp);
    if (value.fail()) {
      LOG(ERROR) << "Failed to parse time: " << datetime;
      return 0;
    }

    return seconds(tp);
  }

@HowardHinnant
Copy link
Owner

What do you think about this?

// parse "%F" or "%FT%TZ"
int64_t
time(const std::string_view datetime)
{
    std::istringstream in{datetime.data()};
    date::sys_seconds tp;
    std::chrono::seconds tod{};
    in >> date::parse("%F", tp);
    if (in.fail())
    {
        std::cerr << "Failed to parse time: " << datetime;
        return 0;
    }
    in >> date::parse("T%TZ", tod);
    tp += tod;
    return tp.time_since_epoch().count();
}

The one thing it might not do right for you is interpret "2021-11-23T20:55:52" as equivalent to "2021-11-23" because of the syntax error in the time part (missing trailing Z). If you want to interpret syntax errors in an attempted time-of-day you could peek into the stream looking for 'T' and then commit to parsing a duration or returning an error.

@shawncao
Copy link
Author

This is pretty smart! Using two steps instead of one, thanks for sharing this!

@shawncao
Copy link
Author

@HowardHinnant may I ask you another question?

What is the name for a date time string like this "2023-09-17 17:08:00.368787+00:00", is this another standard?
What pattern format to use to parse date time string like this?

@HowardHinnant
Copy link
Owner

Not sure about a standard name. But this will parse it:

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace chrono;

    istringstream in{"2023-09-17 17:08:00.368787+00:00"};
    sys_time<microseconds> tp;
    in >> parse("%F %T%Ez", tp);
    cout << tp << '\n';
}

@shawncao
Copy link
Author

Awesome, thank you again!

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

No branches or pull requests

2 participants