2

I would like to convert string data to struct tm (c) or std::chrono::time_point. The problem is I wanna working solution for both standard libc (glibc and musl). I have tree standard formats that I wanna parse.

  1. RFC-1123

    Sun, 06 Nov 1994 08:49:37 GMT

  2. RFC-850

    "Sunday, 06-Nov-94 08:49:37 GMT"

  3. ANSI C's asctime format

    Sun Nov 6 08:49:37 1994"

Is there any way to make it work? std::get_time has a bug
strptime work fine (and quick) on glibc but fail against musl.

Any idea? I don't wanna use stream like in get_time. But If it would be necessary that fine. (It's ok to use GCC5> and c++11 standard)

Tony Tannous
  • 14,154
  • 10
  • 50
  • 86
S.R
  • 2,411
  • 1
  • 22
  • 33

1 Answers1

1

Howard Hinnant's free, open source, header-only, date/time library can parse these formats into a std::chrono::time_point, even in the context of faulty get_time and strptime facilities. It does require the use of std::istringstream though. Here is what it looks like:

#include "date.h"
#include <sstream>

std::chrono::system_clock::time_point
parse_RFC_1123(const std::string& s)
{
    std::istringstream in{s};
    std::chrono::system_clock::time_point tp;
    in >> date::parse("%a, %d %b %Y %T %Z", tp);
    return tp;
}

std::chrono::system_clock::time_point
parse_RFC_850(const std::string& s)
{
    std::istringstream in{s};
    std::chrono::system_clock::time_point tp;
    in >> date::parse("%a, %d-%b-%y %T %Z", tp);
    return tp;
}

std::chrono::system_clock::time_point
parse_asctime(const std::string& s)
{
    std::istringstream in{s};
    std::chrono::system_clock::time_point tp;
    in >> date::parse("%a %b %d %T %Y", tp);
    return tp;
}

This can be exercised like this:

#include <iostream>

int
main()
{
    auto tp = parse_RFC_1123("Sun, 06 Nov 1994 08:49:37 GMT");
    using namespace date;
    std::cout << tp << '\n';
    tp = parse_RFC_850("Sunday, 06-Nov-94 08:49:37 GMT");
    std::cout << tp << '\n';
    tp = parse_asctime("Sun Nov 6 08:49:37 1994");
    std::cout << tp << '\n';
}

and outputs:

1994-11-06 08:49:37.000000
1994-11-06 08:49:37.000000
1994-11-06 08:49:37.000000

The parse flags %a and %b are normally locale-dependent. However if you compile this library with -DONLY_C_LOCALE=1 it becomes locale independent. It should give the same result either way. But from a practical standpoint, if you compile without -DONLY_C_LOCALE=1 and you don't get the results above, you have to submit a bug report to your std::lib vendor.

If you compile with -DONLY_C_LOCALE=1 and you don't get the results above, rattle my cage, and I will have it fixed within days, if not hours.

S.R
  • 2,411
  • 1
  • 22
  • 33
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • Thanks for answer! I did some benchmarks on your function. I can't understand why your solution is quicker than `sprintf` in RFC850 case. Even that you use streams. Benchmark can be found [here](https://github.com/oktal/pistache/pull/102#issuecomment-322527542). – S.R Aug 19 '17 at 15:21
  • I don't get the same result with and without `-DONLY_C_LOCALE=1` for RFC 850. I would like to submit bug. But have no idea who is my std::lib vendor. If I use GCC 7, should I report it there? – S.R Sep 04 '17 at 20:16
  • What is more, my benchmarks was wrong, RFC850 parser fail and due to it was quicker than `strptime`. No it's slower, but works fine. – S.R Sep 04 '17 at 20:23