How to Format a Datetime to String Using Boost

How to format a datetime to string using boost?

For whatever it is worth, here is the function that I wrote to do this:

#include "boost/date_time/posix_time/posix_time.hpp"
#include <iostream>
#include <sstream>

std::wstring FormatTime(boost::posix_time::ptime now)
{
using namespace boost::posix_time;
static std::locale loc(std::wcout.getloc(),
new wtime_facet(L"%Y%m%d_%H%M%S"));

std::basic_stringstream<wchar_t> wss;
wss.imbue(loc);
wss << now;
return wss.str();
}

int main() {
using namespace boost::posix_time;
ptime now = second_clock::universal_time();

std::wstring ws(FormatTime(now));
std::wcout << ws << std::endl;
sleep(2);
now = second_clock::universal_time();
ws = FormatTime(now);
std::wcout << ws << std::endl;

}

The output of this program was:

20111130_142732
20111130_142734

I found these links useful:

  • How to format date time object with format dd/mm/yyyy?
  • http://www.boost.org/doc/libs/1_35_0/doc/html/date_time/date_time_io.html#date_time.time_facet
  • http://www.cplusplus.com/reference/iostream/stringstream/str/

Using boost parse datetime string: With single digit hour format

I'll leave it to you to sort out how you want dates without years to be interpreted. However, here's a quick start using /just/ strptime.

I used it in a larger codebase, and we needed some pretty versatile date recognition. Behold: the adaptive datetime parser:

#pragma once

#include <string>
#include <chrono>
#include <cstdint>
#include <list>

namespace mylib { namespace datetime {

/*
* Multi-format capable date time parser
*
* Intended to be seeded with a list of supported formats, in order of
* preference. By default, parser is not adaptive (mode is `fixed`).
*
* In adaptive modes the format can be required to be
*
* - sticky (consistently reuse the first matched format)
* - ban_failed (remove failed patterns from the list; banning only occurs
* on successful parse to avoid banning all patterns on invalid input)
* - mru (preserves the list but re-orders for performance)
*
* CAUTION:
* If formats are ambiguous (e.g. mm-dd-yyyy vs dd-mm-yyyy) allowing
* re-ordering results in unpredictable results.
* => Only use `mru` when there are no ambiguous formats
*
* NOTE:
* The function object is stateful. In algorithms, pass it by reference
* (`std::ref(obj)`) to avoid copying the patterns and to ensure correct
* adaptive behaviour
*
* NOTE:
* - use %z before %Z to correctly handle [-+]hhmm POSIX TZ indications
* - adaptive_parser is thread-safe as long as it's not in any adaptive
* mode (the only allowed flag is `full_match`)
*/
class adaptive_parser {
public:
typedef std::list<std::string> list_t;

enum mode_t {
fixed = 0, // not adapting; keep trying same formats in same order
sticky = 1, // re-use first successful format consistently
ban_failed = 2, // forget formats that have failed
mru = 4, // optimize by putting last known good in front
full_match = 8, // require full matches to be accepted
};

adaptive_parser(mode_t m = full_match);
adaptive_parser(mode_t m, list_t formats);

// returns seconds since epoch
std::chrono::seconds operator()(std::string);

private:
mode_t _mode;
list_t _formats;
};

static inline adaptive_parser::mode_t operator|(adaptive_parser::mode_t lhs, adaptive_parser::mode_t rhs) {
return static_cast<adaptive_parser::mode_t>(static_cast<int>(lhs) | static_cast<int>(rhs));
}

} }

You can use it as such:

Live On Wandbox

#include "adaptive_parser.h"
#include <string>
#include <iostream>

int main() {
using namespace mylib::datetime;

adaptive_parser parser { adaptive_parser::full_match, {
"%Y %dth %B %H:%M %p",
"%dth %B %H:%M %p",
"%Y %dth %B %I:%M %p",
"%dth %B %I:%M %p",
} };

for (std::string const input : {
"2017 28th january 11:50 PM",
"28th january 11:50 PM",
"2017 28th january 1:50 PM",
"28th january 1:50 PM",
})
try {
std::cout << "Parsing '" << input << "'\n";
std::cout << " -> epoch " << parser(input).count() << "\n";
} catch(std::exception const& e) {
std::cout << "Exception: " << e.what() << "\n";
}
}

Printing:

Parsing '2017 28th january 11:50 PM'
-> epoch 1485604200
Parsing '28th january 11:50 PM'
-> epoch -2206613400
Parsing '2017 28th january 1:50 PM'
-> epoch 1485568200
Parsing '28th january 1:50 PM'
-> epoch -2206649400

Note that epoch -2206613400 corresponds to 28 jan 1900

Implementation

The implementation comes with a bunch of pretty well-tuned unambiguous date patterns. Our project used a number of "hacks" to normalize strange input formats, these have been omitted (you can see the commented references to detail::normalize_... functions for ideas):

#include "adaptive_parser.h"
#include "time.h"
#include <vector>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>

namespace {
enum level { LOG_DEBUG };
static std::ostream s_devnull { nullptr };

struct {
std::ostream& log(int) const {
#ifdef NDEBUG
return s_devnull;
#else
return std::cerr;
#endif
};
} s_trace;
}

namespace mylib { namespace datetime {

adaptive_parser::adaptive_parser(mode_t m)
: _mode(m), _formats {
// use EOL_MARK to debug patterns when you suspect ambiguity or partial matches
#define EOL_MARK "" // " EOL_MARK"
// use %z before %Z to correctly handle [-+]hhmm POSIX time zone offsets
#if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 15
// ubuntu 12.04 used eglibc and doesn't parse all bells and whistles
#define WITH_TZ(prefix, suffix) prefix " %z" suffix, prefix " %Z" suffix, prefix " Z" suffix, prefix " (UTC)" suffix, prefix suffix
#else
#define WITH_TZ(prefix, suffix) prefix " %z" suffix, prefix " %Z" suffix, prefix suffix
#endif
WITH_TZ("%Y-%m-%dT%H:%M:%S.%f", EOL_MARK),
WITH_TZ("%Y-%m-%dT%H:%M:%S", EOL_MARK),
WITH_TZ("%Y-%m-%dT%H:%M", EOL_MARK),
//
WITH_TZ("%Y-%m-%dT%I:%M:%S.%f %p", EOL_MARK),
WITH_TZ("%Y-%m-%dT%I:%M:%S %p", EOL_MARK),
WITH_TZ("%Y-%m-%dT%I:%M %p", EOL_MARK),
//
WITH_TZ("%Y-%m-%d%n%H:%M:%S", EOL_MARK),
WITH_TZ("%Y-%m-%d%n%I:%M:%S %p", EOL_MARK),
//
WITH_TZ("%a %b %d %H:%M:%S %Y", EOL_MARK),
WITH_TZ("%a %b %d %I:%M:%S %p %Y", EOL_MARK),
//
WITH_TZ("%a %d %b %H:%M:%S %Y", EOL_MARK),
WITH_TZ("%a %d %b %I:%M:%S %p %Y", EOL_MARK),
//
WITH_TZ("%a, %b %d %H:%M:%S %Y", EOL_MARK),
WITH_TZ("%a, %b %d %I:%M:%S %p %Y", EOL_MARK),
//
WITH_TZ("%a, %d %b %H:%M:%S %Y", EOL_MARK),
WITH_TZ("%a, %d %b %I:%M:%S %p %Y", EOL_MARK),
//////
WITH_TZ("%a %d %b %Y %H:%M:%S", EOL_MARK),
WITH_TZ("%a %d %b %Y %I:%M:%S %p", EOL_MARK),
//
WITH_TZ("%a, %d %b %Y %H:%M:%S", EOL_MARK),
WITH_TZ("%a, %d %b %Y %I:%M:%S %p", EOL_MARK),
#undef WITH_TZ
/*
* HUMAN DATE:
*
* This pattern would ambiguate the "%s" one (sadly, because it
* leads to obviously bogus results like parsing "1110871987" into
* "2063-04-24 16:25:59" (because "1110-8-7T19:8:7" matches
* "%Y-%m-%dT%H:%M:%S %Z" somehow...).
*
* We work around this issue by normalizing detected
* 'yyyyMMddhhmmss' human dates into iso format as a preprocessing
* step.
*/
//"%Y %m %d %H %M %S" EOL_MARK,

// epoch seconds
"@%s" EOL_MARK,
"%s" EOL_MARK,
}
{ }

adaptive_parser::adaptive_parser(mode_t m, list_t formats)
: _mode(m), _formats(std::move(formats))
{ }

std::chrono::seconds adaptive_parser::operator()(std::string input) {
if (_formats.empty()) throw std::invalid_argument("No candidate patterns in datetime::adaptive_parser");
if (input.empty()) throw std::invalid_argument("Empty input cannot be parsed as a date time");

//detail::normalize_tz(input);
//detail::normalize_tz_utc_w_offset_re(input);
//detail::normalize_date_sep(input);
//detail::normalize_human_date(input);
//detail::normalize_redundant_timezone_description(input);
input += EOL_MARK;

std::vector<list_t::iterator> failed;

bool matched = false;
struct tm time_struct;

auto pattern = _formats.begin();
for (; !matched && pattern != _formats.end(); ++pattern) {
memset(&time_struct, 0, sizeof(time_struct));
auto tail = ::strptime(input.c_str(), pattern->c_str(), &time_struct);

matched = tail;
//if (matched) s_trace.log(LOG_DEBUG) << "Input '" << input << "' successfully matched pattern '" << *pattern << "' leaving '" << tail << "'\n";

if (_mode & full_match) {
while (tail && *tail && std::isspace(*tail))
++tail; // skip trailing whitespace
matched &= tail && !*tail;
}

if (matched)
break;

if (_mode & ban_failed)
failed.push_back(pattern);
}

if (matched) {
for (auto to_ban : failed) {
s_trace.log(LOG_DEBUG) << "Banning failed datetime pattern: " << *to_ban << "\n";
_formats.erase(to_ban);
}

if (_mode & sticky) {
s_trace.log(LOG_DEBUG) << "Made succeeding datetime pattern sticky: " << *pattern << "\n";
_formats = { *pattern };
}

if ((_mode & mru) && pattern != _formats.begin()) {
assert(pattern != _formats.end()); // inconsistent with `matched==true`

s_trace.log(LOG_DEBUG) << "Promote succeeding datetime pattern to the top: " << *pattern << "\n";
std::rotate(_formats.begin(), pattern, std::next(pattern));
}
#ifdef __FreeBSD__
auto raw = (time_struct.tm_gmtoff)? mktime(&time_struct) : timegm(&time_struct);
return std::chrono::seconds(raw);
#else
long offset = time_struct.tm_gmtoff;
return std::chrono::seconds(timegm (&time_struct) - offset);
#endif
}

s_trace.log(LOG_DEBUG) << "Failed to parse datetime input '" << input << "' with " << _formats.size() << " patterns\n";
throw std::runtime_error("Input cannot be parsed as a date time");
}

} }

Parse datetime with timezone using Boost.Date_Time?

I've looked at it long and hard. It seems you're almost completely out of luck:

Sample Image


So you can try making it work with %ZP.

Doing The Heroics

I did the heroics, only to find out that the support for wtime_zone and friends is ... incomplete in the library.

Here it is in all it g(l)ory:

Live On Coliru

#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/time_zone_base.hpp>
#include <ctime>
#include <chrono>
#include <sstream>

namespace DT = boost::date_time;
namespace LT = boost::local_time;
namespace PT = boost::posix_time;

template <typename CharT = wchar_t> struct TypeDefs {
using ptime = PT::ptime;
using tz_base = DT::time_zone_base<ptime, CharT>;
using tz_ptr = boost::shared_ptr<DT::time_zone_base<PT::ptime, CharT> >;
using ptz_t = LT::posix_time_zone_base<CharT>;
using ldt_t = LT::local_date_time_base<ptime, tz_base>;
};

namespace boost { namespace local_time {
//! input operator for local_date_time
template <class CharT, class Traits, typename Defs = TypeDefs<CharT>, typename local_date_time = typename Defs::ldt_t>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, local_date_time& ldt)
{
using time_zone_ptr = typename Defs::tz_ptr;
using posix_time_zone = typename Defs::ptz_t;
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename local_date_time::utc_time_type utc_time_type;
typedef typename date_time::time_input_facet<utc_time_type, CharT> time_input_facet;

// intermediate objects
std::basic_string<CharT> tz_str;
utc_time_type pt(DT::not_a_date_time);

std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<time_input_facet>(is.getloc())) {
std::use_facet<time_input_facet>(is.getloc()).get_local_time(sit, str_end, is, pt, tz_str);
}
else {
time_input_facet* f = new time_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get_local_time(sit, str_end, is, pt, tz_str);
}
if(tz_str.empty()) {
time_zone_ptr null_ptr;
// a null time_zone_ptr creates a local_date_time that is UTC
ldt = local_date_time(pt, null_ptr);
}
else {
time_zone_ptr tz_ptr(new posix_time_zone(tz_str));
// the "date & time" constructor expects the time label to *not* be utc.
// a posix_tz_string also expects the time label to *not* be utc.
ldt = local_date_time(pt.date(), pt.time_of_day(), tz_ptr, local_date_time::EXCEPTION_ON_ERROR);
}
}
catch(...) {
// mask tells us what exceptions are turned on
std::ios_base::iostate exception_mask = is.exceptions();
// if the user wants exceptions on failbit, we'll rethrow our
// date_time exception & set the failbit
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {} // ignore this one
throw; // rethrow original exception
}
else {
// if the user want's to fail quietly, we simply set the failbit
is.setstate(std::ios_base::failbit);
}

}
}
return is;
}
} }

template <typename CharT = wchar_t> struct DateUtilsBase : TypeDefs<CharT> {

using base = TypeDefs<CharT>;
using typename base::ldt_t;
using typename base::tz_ptr;
using typename base::ptime;

static std::tm to_tm(ldt_t const& lt) {
std::tm v = PT::to_tm(lt.local_time());
v.tm_isdst = lt.is_dst()? 1:0;
return v;
}

static tz_ptr s_GMT;

static std::chrono::system_clock::time_point Parse(const std::basic_string<CharT>& dateText, const CharT* const format) {

ldt_t value(LT::special_values::not_a_date_time, s_GMT);

std::basic_istringstream<CharT> buffer(dateText);
buffer.imbue(std::locale(std::locale::classic(), new DT::time_input_facet<ptime, CharT>(format)));

std::basic_string<CharT> dummy;
if (buffer >> value && (buffer >> dummy).eof()) {
std::cout << "DEBUG: " << value.utc_time() << " EOF:" << buffer.eof() << "\n";
auto timeInfo = PT::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}
}
};

template <> typename DateUtilsBase<wchar_t>::tz_ptr DateUtilsBase<wchar_t>::s_GMT { new ptz_t(L"GMT") } ;
template <> typename DateUtilsBase<char>::tz_ptr DateUtilsBase<char>::s_GMT { new ptz_t("GMT") } ;

#if 1
using DateUtils = DateUtilsBase<wchar_t>;
#define T(lit) L##lit
#else
using DateUtils = DateUtilsBase<char>;
#define T(lit) lit
#endif

int main() {
using namespace std::chrono_literals;
using C = std::chrono::system_clock;
std::cout << std::boolalpha << std::unitbuf;

C::time_point with_zone, without_zone;

// all three equivalent:
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01 PST-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01 -05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse(T("2016-12-03T07:09:01-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));

without_zone = DateUtils::Parse(T("2016-12-03T07:09:01"), T("%Y-%m-%dT%H:%M:%S"));
std::cout << "time_point equal? " << (with_zone == without_zone) << "\n";

{
std::time_t t_with_zone = C::to_time_t(with_zone);
std::time_t t_without_zone = C::to_time_t(without_zone);

std::cout << "time_t equal? " << (t_with_zone == t_without_zone) << "\n";
}

std::cout << (without_zone - with_zone) / 1h << " hours difference\n";
}

Yep. That's a bit of a monstrosity. It prints:

DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 12:09:01 EOF:true
DEBUG: 2016-Dec-03 07:09:01 EOF:true
time_point equal? false
time_t equal? false
-5 hours difference

Back To Sanity

In fact, the library authors (wisely) decided that even though streams would be wide or narrow, the local_date_time (or really, just the strings in their time-zone representations) need not be. This is why the library supplied operator>> only supports local_date_time and employs the internal helper function convert_string_type to coerce to narrow-char timezone info:

time_zone_ptr tz_ptr(new posix_time_zone(date_time::convert_string_type<CharT,char>(tz_str)));

With that in mind let's remove a lot "generic-y" cruft. What remains is the addition of error-handling:

if (buffer >> value && (buffer >> dummy).eof()) {
//std::cout << "DEBUG: " << value.utc_time() << " EOF:" << buffer.eof() << "\n";
auto timeInfo = boost::posix_time::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}

Live On Coliru

#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <ctime>
#include <chrono>
#include <sstream>

struct DateUtils {
using ptime = boost::posix_time::ptime;
using time_zone_ptr = boost::local_time::time_zone_ptr;
using local_date_time = boost::local_time::local_date_time;

template <typename CharT>
static std::chrono::system_clock::time_point Parse(const std::basic_string<CharT>& dateText, const CharT* const format) {
static time_zone_ptr s_GMT(new boost::local_time::posix_time_zone("GMT"));

local_date_time value(boost::local_time::special_values::not_a_date_time, s_GMT);

std::basic_istringstream<CharT> buffer(dateText);
buffer.imbue(std::locale(std::locale::classic(), new boost::date_time::time_input_facet<ptime, CharT>(format)));

std::basic_string<CharT> dummy;
if (buffer >> value && (buffer >> dummy).eof()) {
//std::cout << "DEBUG: " << value.utc_time() << " EOF:" << buffer.eof() << "\n";
auto timeInfo = boost::posix_time::to_tm(value.utc_time());
return std::chrono::system_clock::from_time_t(std::mktime(&timeInfo));
} else {
return std::chrono::system_clock::time_point::min();
}
}
};

#if 1
using CharT = wchar_t;
#define T(lit) L##lit
#else
using CharT = char;
#define T(lit) lit
#endif

int main() {
using namespace std::chrono_literals;
using C = std::chrono::system_clock;
std::cout << std::boolalpha << std::unitbuf;

C::time_point with_zone, without_zone;

// all three equivalent:
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01 PST-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01 -05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));
with_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01-05:00"), T("%Y-%m-%dT%H:%M:%S%ZP"));

without_zone = DateUtils::Parse<CharT>(T("2016-12-03T07:09:01"), T("%Y-%m-%dT%H:%M:%S"));
std::cout << "time_point equal? " << (with_zone == without_zone) << "\n";

{
std::time_t t_with_zone = C::to_time_t(with_zone);
std::time_t t_without_zone = C::to_time_t(without_zone);

std::cout << "time_t equal? " << (t_with_zone == t_without_zone) << "\n";
}

std::cout << (without_zone - with_zone) / 1h << " hours difference\n";
}

Whew. From 151 LoC down to 64 LoC. Better

Prints:

time_point equal? false
time_t equal? false
-5 hours difference

Summary:

  • read (all) the notes in the docs
  • use %ZP as the only supported input format
  • use local_date_time because that format string is ignored with ptime (it says so in the notes)
  • use error handling to make sure no "unparsed" things are left behind in the input

How to convert a boost::ptime to string

The Boost.Date_Time library provides the following ptime to std::string conversions within the boost::posix_time namespace:

  • std::string to_simple_string(ptime) returns a string in the form of YYYY-mmm-DD HH:MM:SS.fffffffff format where mmm is the three character month name.
  • std::string to_iso_string(ptime) returns a string in the form of YYYYMMDDTHHMMSS,fffffffff where T is the date-time separator.
  • std::string to_iso_extended_string(ptime) returns a string in the form of YYYY-MM-DDTHH:MM:SS,fffffffff where T is the date-time separator.

Additionally, stream insertion and extraction operators are provided, allowing ptime to be inserted or extracted from a stream. The input and output formats can be customized by constructing facets with various format flags, and then imbuing the stream with the facet.

Based on the compile error (C2220), the compiler is set to treat all warnings as errors. In some cases, the Boost libraries will compile with warnings. Consider assessing the severity of the actual warning, and handling it appropriately from there. For example, if the warning is trivial, it may be acceptable to use a warning pragma to disable or suppress the specific warning.


Here is a complete example demonstrating converting ptime to a string via its provided conversion functions and stream operators.

#include <iostream>
#include <locale>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>

int main()
{
const boost::posix_time::ptime time =
boost::posix_time::time_from_string("1981-08-20 08:05:00");

// ptime to string.
const std::string str_time = to_simple_string(time);
std::cout << str_time << std::endl;

// ptime to stringstream to string.
std::stringstream stream;
stream << time;
std::cout << stream.str() << std::endl;
stream.str("");

// Use a facet to display time in a custom format (only hour and minutes).
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet();
facet->format("%H:%M");
stream.imbue(std::locale(std::locale::classic(), facet));
stream << time;
std::cout << stream.str() << std::endl;
}

Which produces the following output:

1981-Aug-20 08:05:00    
1981-Aug-20 08:05:00
08:05

How do I parse datetime with boost::karma/qi?

Spirit Karma is meant for generating output, not for parsing, so no you cannot use it for that.

For a job like this I'd suggest not parsing the entire date format, but instead the general form of the line as you gave it:

<line id>,<time>,<data_1>,<data_2>,<event_description>

Let's define a recipient type:

struct Event {
size_t id;
std::string date, data1, data2, description;
};

Adapt it for automatic attribute propagation:

BOOST_FUSION_ADAPT_STRUCT(Event, id, date, data1, data2, description)

A simple rule for it:

qi::rule<boost::spirit::istream_iterator, Event(), qi::blank_type> rule;
rule =
qi::ulong_long >> ',' >> // id
qi::raw[*~qi::char_(',')] >> ',' >> // date
qi::raw[*~qi::char_(',')] >> ',' >> // data1
qi::raw[*~qi::char_(',')] >> ',' >> // data2
qi::raw[*(qi::char_ - qi::eol)] // description
;

And here we go:

if (qi::phrase_parse(f, l, rule % qi::eol, qi::blank, events)) {
for (auto& event : events) {
std::cout << event << "\n----\n";
}
} else {
std::cout << "Parse failed\n";
}

if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << "\n";
}

Prints: Live On Coliru

         id:11886
date:"05/09/20 01:01:06.338053260"
data1:"26168"
data2:"5374"
description:"if (_mode & full_match) {"

----
id:30215
date:"05/09/20 01:01:15.391796323"
data1:"23936"
data2:"15742"
description:"auto const& shape = shapes.at(id);"

----
id:7386
date:"05/09/20 01:01:15.463584888"
data1:"26798"
data2:"13486"
description:"into.emplace_back();"

----
id:24377
date:"05/09/20 01:01:15.531308865"
data1:"11735"
data2:"15257"
description:"auto pattern = _formats.begin();"

----
id:11744
date:"05/09/20 01:01:15.590114069"
data1:"3451"
data2:"17645"
description:"auto bounds = field.bounds();"

----
id:20148
date:"05/09/20 01:01:15.652360522"
data1:"12228"
data2:"29033"
description:"if ((_mode & mru) && pattern != _formats.begin()) {"

----
id:9196
date:"05/09/20 01:01:15.699402632"
data1:"6639"
data2:"27448"
description:"#include <boost/archive/text_oarchive.hpp>"

----
id:7341
date:"05/09/20 01:01:15.754603212"
data1:"21142"
data2:"30650"
description:"namespace attrs = boost::log::attributes;"

----
id:14990
date:"05/09/20 01:01:15.802583615"
data1:"18421"
data2:"10623"
description:"BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {"

----
id:19490
date:"05/09/20 01:01:15.860306470"
data1:"2883"
data2:"848"
description:"void Server::getNextSamples(std::vector<sf::Int16> oSamples) {"

----
id:30360
date:"05/09/20 01:01:15.918505128"
data1:"4369"
data2:"1998"
description:"case shape::circle: return os << \"circle\";"

----
Remaining unparsed: "
"

Full Listing

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <iostream>
#include <iomanip>

struct Event {
size_t id;
std::string date, data1, data2, description;
};

// for parsing
BOOST_FUSION_ADAPT_STRUCT(Event, id, date, data1, data2, description)

// for debug output
static std::ostream& operator<<(std::ostream& os, Event const& evt) {
os << " id:" << evt.id << "\n";
os << " date:" << std::quoted(evt.date) << "\n";
os << " data1:" << std::quoted(evt.data1) << "\n";
os << " data2:" << std::quoted(evt.data2) << "\n";
os << "description:" << std::quoted(evt.description) << "\n";
return os;
}

int main() {
//<line id>,<time>,<data_1>,<data_2>,<event_description>
std::istringstream iss(R"(11886,05/09/20 01:01:06.338053260,26168,5374, if (_mode & full_match) {
30215,05/09/20 01:01:15.391796323,23936,15742, auto const& shape = shapes.at(id);
7386,05/09/20 01:01:15.463584888,26798,13486, into.emplace_back();
24377,05/09/20 01:01:15.531308865,11735,15257, auto pattern = _formats.begin();
11744,05/09/20 01:01:15.590114069,3451,17645, auto bounds = field.bounds();


Related Topics



Leave a reply



Submit