boost last_write_time is back one hour - boost

I have trying to solve a bug on the following code, where I get an hour difference from boost last_write_time.
To explain it better: I create a file, and then I try to extract the time it was created with boost::filesystem::path.
void PrintTime(boost::filesystem::path _file) {
time_t sys_time{ last_write_time(_file) };
ptime p_time{ boost::posix_time::from_time_t(sys_time) };
boost::posix_time::time_duration time_dur{ p_time.time_of_day() };
long h{ time_dur.hours() }; //1a
long m{ time_dur.minutes() };
long s{ time_dur.seconds() };
//...print h, m, s.
}
//1a: Here when for example the time I expect is 12:34:56,
//I always get 11:34:56
Any idea why is that?
Is there timezone somewhere in boost last_write_time?
My os displays the right time when I check the file through the system.

You have to translate to the "presentation" time-zone, like "when [you] check the file through the system". The timestamp from the filesystem is UTC time.
E.g. if you do
std::cout << boost::posix_time::second_clock::local_time() << "\n";
std::cout << boost::posix_time::second_clock::universal_time() << "\n";
you'll probably get
2018-Feb-27 16:03:12
2018-Feb-27 15:03:12
Fix:
#include <boost/date_time/c_local_time_adjustor.hpp>
void PrintTime(boost::filesystem::path _file) {
using boost::posix_time::ptime;
using adj = boost::date_time::c_local_adjustor<ptime>;
time_t const sys_time = last_write_time(_file);
ptime const utc = boost::posix_time::from_time_t(sys_time);
ptime const local = adj::utc_to_local(utc);
DEMO
See it Live On Coliru
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>
void PrintTime(boost::filesystem::path _file) {
using boost::posix_time::ptime;
using adj = boost::date_time::c_local_adjustor<ptime>;
time_t const sys_time = last_write_time(_file);
ptime const utc = boost::posix_time::from_time_t(sys_time);
ptime const local = adj::utc_to_local(utc);
std::cout << "utc: " << utc << "\n";
std::cout << "local: " << local << "\n";
{
long h{ local.time_of_day().hours() };
long m{ local.time_of_day().minutes() };
long s{ local.time_of_day().seconds() };
//...print h, m, s.
std::cout << h << ":" << m << ":" << s << '\n';
}
}
int main() {
PrintTime("main.cpp");
}
Prints (on my system):
utc: 2018-Feb-27 15:19:45
local: 2018-Feb-27 16:19:45
16:19:45

Related

apply 'with<>' to a skipper parser to get context

My first version of this question was rich with misunderstandings. My answer below suits my needs. But I kept at it to understand what could be done with with<>. What I get is that it intended to inject context into a parser. Then the parser is called from with_directive::parse (in x3's with.hpp) In the following code, that is just what happens.
#include <boost/spirit/home/x3.hpp>
using namespace boost::spirit::x3;
struct eol_parser_cnt : parser<eol_parser_cnt>
{
struct context {
int line = 0;
std::string::iterator iter_pos;
};
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
{
//std::cout << context.line;
auto& ctx = context;
return boost::spirit::x3::parse(first, last, lit(' ') | (lit("//") >> *(char_ - eol) >> eol));
}
};
const auto& our_skipper = eol_parser_cnt{};
eol_parser_cnt::context lines;
auto with_skipper = with<eol_parser_cnt::context>(lines)[our_skipper];
int main()
{
std::string str("12 word");
auto first = str.begin();
phrase_parse(first, str.end(), int_ >> *char_("a-z"), with_skipper);
}
Putting a break point in eol_parser_cnt::parse and I see it working. The debugger consistently shows the context is there and that it is the structure of eol_parser_cnt::context. I can change the value of line in the debugger and the next hit shows that value, it is a real object. But, try to uncomment the line std::cout << context.line; and the compiler complains that is it an unused_type. So, I just don't get it.
test.cpp(15,30): error C2039: 'line': is not a member of 'boost::spirit::x3::context<ID,T,Context>'
with
[
ID=eol_parser_cnt::context,
T=eol_parser_cnt::context,
Context=boost::spirit::x3::unused_type
]
F:\cpp\boost_1_76_0\boost\spirit\home\x3\support\context.hpp(18): message : see declaration of 'boost::spirit::x3::context<ID,T,Context>'
with
[
ID=eol_parser_cnt::context,
T=eol_parser_cnt::context,
Context=boost::spirit::x3::unused_type
]
F:\cpp\boost_1_76_0\boost\spirit\home\x3\directive\with.hpp(62): message : see reference to function template instantiation 'bool eol_parser_cnt::parse<Iterator,boost::spirit::x3::context<ID,T,Context>,Attribute>(Iterator &,const Iterator &,const boost::spirit::x3::context<ID,T,Context> &,boost::spirit::x3::unused_type,Attribute &) const' being compiled
with
[
Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
ID=eol_parser_cnt::context,
T=eol_parser_cnt::context,
Context=boost::spirit::x3::unused_type,
Attribute=const boost::spirit::x3::unused_type
]
Well, it took a while but I was going to understand this. I re-read C++ Template Metaprogramming seriously this time. Then looking at the x3 code I finally understood that with<> is just another parser wrapper. It is interesting to debug an optimized build and see just how much code disappears. VS shows all the disappeared stuff on the stack as inlined and what was 9 layers of parser calls becomes 2 into the likes of with_error_handling::on_error. Everything from my call to parse_rhs_main (in rule.hpp, line 232), is gone.
So because with<> is just another parser wrapper and if the skipper is wrapped, the context is only avaliable to the skipper. But no big deal as the skipper is in the context of the main parser. The difference is that in the skipper object a get<skipper_eol_cnt>(context) returns a reference to the skipper_eol_cnt::context{}. Whereas in the main parser we have to us get<skipper_tag>(context) and this returns the with<> parser object. val is a member of that parser, the reference to the skipper_eol_cnt::context{}. So get<skipper_tag>(context).val retrieves the context we are looking for.
So here it is, using with<> applied to a skipper.
#include<iostream>
#include <iomanip>
#include <vector>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
using namespace boost::spirit::x3;
struct skipper_eol_cnt : parser<skipper_eol_cnt>
{
struct context {
int line = 1;
std::string::iterator iter_pos;
};
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
{
const char* start_cmt = "/*";
const char* end_cmt = "*/";
if (first == last)
return false;
bool matched = false;
//here we are getting from the 'with<>' wrapper
auto& ctx = get<skipper_eol_cnt>(context);
//skip: space | '//comment'
boost::spirit::x3::parse(first, last, lit(' ') | (lit("//") >> *(char_ - eol)));//eol counted below
//skip: '/*comment*/'
if (detail::string_parse(start_cmt, first, last, unused, case_compare<Iterator>())) {
for (; first != last; ++first) {
if (detail::string_parse(end_cmt, first, last, unused, case_compare<Iterator>()))
break;
if (*first == '\n')
++ctx.line, ctx.iter_pos = first;
}
}
Iterator iter = first;
for (; iter != last && (*iter == '\r' || *iter == '\n'); ++iter) {
matched = true;
if (*iter == '\n') // LF
++ctx.line, ctx.iter_pos = iter;
}
//{static int pos = 0; if (pos < ctx.line) { pos = ctx.line; std::cout << pos << std::endl; }}
if (matched) first = iter;
return matched;
}
};
auto const& skip_eol_cnt = skipper_eol_cnt{};
struct with_error_handling {
template<typename It, typename Ctx>
error_handler_result on_error(It f, It l, expectation_failure<It> const& ef, Ctx const& ctx) const {
It erit = f + std::distance(f, ef.where());
//here we are getting the wrapped skipper so need the 'with<>.val'
const auto& sctx = get<skipper_tag>(ctx).val;
It bit = erit;
for (; *bit != '\n'/* && bit != f*/; --bit)
;
It eit = erit;
for (; *eit != '\n' && eit != l; ++eit)
;
int str_pos = erit - bit - 1;
std::ostringstream oss;
oss << "Expecting " << ef.which() << "\n at line: " << sctx.line
<< "\n\t" << std::string(bit + 1, eit)
<< "\n\t" << std::setw(str_pos) << std::setfill('-') << "" << "^";
get<with_error_handling>(ctx).push_back(oss.str());;
return error_handler_result::fail;
}
};
//attr sections
struct section_type {
std::string name;
int line;
std::string::iterator iter_pos;
};
BOOST_FUSION_ADAPT_STRUCT(section_type, name)
using sections_type = std::vector<section_type>;
struct parser_find_sections : parser<parser_find_sections> {
template<typename Iterator, typename Context, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last, Context const& context, RContext const& rcontext, Attribute& section) const {
const auto& sssctx = get<skipper_eol_cnt>(context); //now here this doesn't work, unused_type, but
const auto& sctx = get<skipper_tag>(context).val;
auto to_line = [&sctx, first](auto& ctx) {
_attr(ctx).line = sctx.line;
//_attr(ctx).iter_pos = first; // this one will get at 'section color(x,x)'
_attr(ctx).iter_pos = _where(ctx).begin(); // this one is '(x,x)'
};
static_assert(BOOST_VERSION / 100 % 1000 >= 77);
////NOTE!!! if you have a boost version of less than 1.77, x3::seek will fail here
////quick fix, copy from: https://github.com/boostorg/spirit/blob/boost-1.78.0/include/boost/spirit/home/x3/directive/seek.hpp
////and paste to your boost file...
return phrase_parse(first, last, *(seek["section"] >> (*alpha)[to_line]), get<skipper_tag>(context), section);
}
};
auto const parse_section = rule<with_error_handling, std::pair<int, int>>("the_sec_parser") = [] {
return '(' > int_ > ',' > int_ > ')';
}();
template<typename T>
std::ostream& operator << (std::ostream& os, std::pair<T, T>& t) {
return os << t.first << ',' << t.second;
}
//errors
std::vector<std::string> errors;
auto with_errors = with<with_error_handling>(errors)[parse_section];
auto test_section = [](auto& content, auto& section) {
//attr
std::pair<int, int> attr;
skipper_eol_cnt::context ctx{ section.line, section.iter_pos };
auto with_skip_cnt = with< skipper_eol_cnt>(ctx)[skip_eol_cnt];
auto first(section.iter_pos);
return std::tuple(phrase_parse(first, content.end(), with_errors, with_skip_cnt, attr), attr);
};
int main() {
std::string str(R"(//line 1
section red(5, 6)
section green( 7, 8) //line 3
section blue(9, 10) //no error
/*comment
bunch of lines of stuff....
*/ section white(11, a 12) //error on line 7
section black( 13,14)
)");
//get the list of sections
auto with_skip_cnt = with<skipper_eol_cnt>(skipper_eol_cnt::context{})[skip_eol_cnt];
sections_type secs;
auto first(str.begin());
phrase_parse(first, str.end(), parser_find_sections(), with_skip_cnt, secs);
for (auto& item : secs)
std::cout << item.name << "\t at line: " << item.line << std::endl;
//section 'blue', at 2, has no error
auto [r, attr] = test_section(str, secs.at(2));
if (r)
std::cout << "\nthe " << secs.at(2).name << " hase vals: " << attr << "\n\n";
//section 'white', at 3, has an error
test_section(str, secs.at(3));
if (errors.size())
std::cout << errors.front() << std::endl;
return 0;
}

Create-Delete directory in a loop - returns success but was not complete at that time

( reported here
https://superuser.com/questions/1511981/windows-10-creating-and-deleting-directory-in-remote-location-netapp-in-a-loop this time with some more data and example program )
I am working on an issue - Create and deletion of directory on a loop in a small window gets incorrect response from API - it says directory deleted (returns true) but it stays there for some more time(say 20-30 milliseconds).
What can cause? The program runs fine on Windows 7 (NetApp storage or local disk). Windows 10 passes with local disk; but fails with NetApp storage. Need to sleep get the API (DeleteDirectory correct )
Wrote a code to reproduce in windows , c program (because admins wanted that way to rule out java, powershell etc )
#include "pch.h"
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <direct.h>
using namespace std;
int main()
{
const char* sleepTimeAsString = std::getenv("SLEEP_TIME_MILLIS");
const char* remoteRoot = std::getenv("REMOTE_UNC_PATH");
if (sleepTimeAsString == NULL) {
std::cout << "env SLEEP_TIME_MILLIS needed: " << '\n';
}
if (remoteRoot == NULL) {
std::cout << "env REMOTE_UNC_PATH needed: " << '\n';
}
std::cout << "set REMOTE_UNC_PATH=" << remoteRoot << '\n';
std::cout << "set SLEEP_TIME_MILLIS=" << sleepTimeAsString << '\n';
CreateDirectory(remoteRoot,NULL);
std::cout << "version 0.10 " << '\n';
std::cout << "created " << remoteRoot << '\n';
string path = remoteRoot;
string mynode = "/childdirectory";
string path2 = path + mynode;
DWORD error= GetLastError();
std::cout << error << '\n';
long sleepTime = atol(sleepTimeAsString);
for (int i = 0; i < 1000; i++) {
std::cout << "loop "<< i << '\n';
if (!CreateDirectory( path2.c_str(), NULL)) {
DWORD errorlooped = GetLastError();
std::cout <<"failed to create " << errorlooped << '\n';
exit(-1);
}
else {
std::cout << "success created " << path2.c_str() << '\n';
}
Sleep(sleepTime);
if (!RemoveDirectory(path2.c_str())) {
DWORD errorlooped = GetLastError();
std::cout << "failed remove "<< errorlooped << '\n';
exit(-1);
}
else {
std::cout << "success deleted " << path2.c_str() << '\n';
}
Sleep(sleepTime);
}
}
Result table: Once I provide sufficient sleep between calls the test started passing on this NetApp directory.
OS Disk Sleep Time(ms) Result
Win7 Local 0 PASS
Win7 Remote 0 PASS
WIn10 Local 0 PASS
WIn10 Remote (NetApp) 0 FAIL
WIn10 Remote (NetApp) 10 FAIL
WIn10 Remote (NetApp) 20 FAIL
WIn10 Remote (NetApp) 40 PASS
What should I investigate more on this issue (before getting back to System administrators ) - Ideas welcome.

Idiomatic complete matching with post skipping

What is the most idiomatic way to do post-skipping? More specific I want to ensure there is no "non-skippable" (garbage) characters in my input after matching my top rule.
auto const blankOrComment
= ascii::space
| x3::lexeme ['#' >> *(x3::char_ - x3::eol) >> -x3::eol ]
;
auto const program = rule<AstProgram>("program")
= *(as<AstDefinition> (definition > ";"))
;
auto const programEntry = x3::skip(blankOrComment) [program];
One idea, I consider quite ugly was to do a separate parse call for the blankOrComment afterwards, if the main iterator position is not the end iterator. The current better idea I have is to change the root rule:
auto const programEntry = x3::skip(blankOrComment) [program >> x3::omit[*blankOrComment]];
Is there a more idiomatic way?
The simplest hack is to tack on >> eps: Live On Coliru
Note I'd strive to make the skipper more self-descriptive:
auto const skipper
= space
| '#' >> *(char_ - eol) >> (eol|eoi)
;
Likewise you can make that postskip hack more self-descriptive:
auto const post_skip = eps;
auto const program = "program" >> post_skip;
Live On Coliru
#include <iostream>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
namespace Parser {
namespace x3 = boost::spirit::x3;
namespace rules {
using namespace x3;
auto const skipper
= space
| '#' >> *(char_ - eol) >> (eol|eoi)
;
auto const post_skip = eps;
auto const program = "program" >> post_skip;
}
auto const programEntry = x3::skip(rules::skipper) [rules::program];
}
int main() {
using It = std::string::const_iterator;
for (std::string const input : {
"",
" program ",
"#hello\n program # comment\n",
}) {
It f = input.begin(), l = input.end();
if(parse(f, l, Parser::programEntry)) {
std::cout << "Parse success\n";
} else {
std::cout << "Parse failed\n";
}
std::cout << "Remaining: '" << std::string(f,l) << "'\n";
}
}
Prints
Parse failed
Remaining: ''
Parse success
Remaining: ''
Parse success
Remaining: ''

File Isn't Deleting

I have a code that finds files that are less than 20 seconds old. It's finding them, but I can't get them deleted. I am using remove(). I've tried using remove with wildcards but no luck. It has to be something with the syntax. Any help is appreciated. Thank you.
using namespace std;
typedef vector<WIN32_FIND_DATA> tFoundFilesVector;
std::wstring LastWriteTime;
int getFileList(const char * filespec, tFoundFilesVector &foundFiles)
{
WIN32_FIND_DATA findData;
HANDLE h;
int validResult=true;
int numFoundFiles = 0;
h = FindFirstFile((LPCSTR)filespec, &findData);
if (h == INVALID_HANDLE_VALUE)
return 0;
while (validResult)
{
numFoundFiles++;
foundFiles.push_back(findData);
validResult = FindNextFile(h, &findData);
}
return numFoundFiles;
}
void showFileAge(tFoundFilesVector &fileList)
{
unsigned _int64 fileTime, curTime, age;
tFoundFilesVector::iterator iter;
FILETIME ftNow;
CoFileTimeNow(&ftNow);
curTime = ((_int64) ftNow.dwHighDateTime << 32) + ftNow.dwLowDateTime;
for (iter=fileList.begin(); iter<fileList.end(); iter++)
{
fileTime = ((_int64)iter->ftLastWriteTime.dwHighDateTime << 32) + iter- >ftLastWriteTime.dwLowDateTime;
age = curTime - fileTime;
if (age <= (_int64)200000000UL)
{
wcout << " Delete: '" <<endl;
wcout << "FILE: '" << iter->cFileName << "', AGE: " << (_int64)age/10000000UL << " seconds" << endl;
remove("C:\\mapper\\iter->cFileName");
}
else
{
//wcout << " Quit: '" <<endl;
//return;
}
}
}
int main()
{
string fileSpec = "*.*";
tFoundFilesVector foundFiles;
tFoundFilesVector::iterator iter;
int foundCount = 0;
getFileList("c:\\Mapper\\*.txt", foundFiles);
getFileList("c:\\Mapper\\*.jpg", foundFiles);
foundCount = foundFiles.size();
if (foundCount)
{
wcout << "Found "<<foundCount<<" matching files.\n";
showFileAge(foundFiles);
}
system("pause");
return 0;
}
You need to concatenate the strings "C:\mapper\" with whatever is in iter->cFileName. The most simple way of doing that would be to use the std::string class.
The result would look something like this:
remove(string("c:\\mapper\\").append(string(iter->cFileName)).c_str());
This assumes you do not use unicode encoding of your strings, otherwise you need to use std::wstring. To use these classes you will also need to include
#include <string>
in the top of your file.

how to customize "TimeStamp" format of Boost.Log

I want to get year-month-day hour:minute:second.fraction(2 digits), if I use "%Y-%m-%d %H:%M:%S.%f", I got almost what I want exception for the fraction( last part ) of seconds, it's showing 6 digits on my Windows XP, I don't know how to get 2 digits only, any idea?
I'm using this
namespace boost
{
BOOST_LOG_OPEN_NAMESPACE
namespace attributes
{
template <typename date_time_type>
void format_time_ms( std::ostringstream& formatter, const date_time_type& date_time)
{
auto time = date_time.time_of_day();
using namespace std;
formatter
<< setfill( '0') << setw( 2) << time.hours() << ':'
<< setfill( '0') << setw( 2) << time.minutes() << ':'
<< setfill( '0') << setw( 2) << time.seconds() << ','
<< setfill( '0') << setw( 3) << time.fractional_seconds() / 1000;
}
template <typename date_time_type>
std::string format_time_ms( const date_time_type& date_time)
{
std::ostringstream formatter;
format_time_ms( formatter, date_time);
auto time = date_time.time_of_day();
return formatter.str();
}
template <typename date_time_type>
std::string format_date_time_ms( const date_time_type& date_time, const char date_time_sep = ' ')
{
using namespace std;
ostringstream formatter;
auto date = date_time.date();
formatter
<< date.year() << '-'
<< setfill( '0') << setw( 2) << int( date.month()) << '-'
<< setfill( '0') << setw( 2) << date.day() << date_time_sep;
format_time_ms( formatter, date_time);
return formatter.str();
}
template <typename date_time_type, const char date_time_sep = ' '>
struct date_time_ms_formatter
{
std::string operator () ( const date_time_type& date_time) { return format_date_time_ms( date_time, date_time_sep); }
};
struct time_ms_formatter
{
template <typename date_time_type>
std::string operator () ( const date_time_type& date_time) { return format_time_ms( date_time); }
};
template <typename time_type>
struct local_clock_source
{
time_type operator () () const
{
return date_time::microsec_clock<time_type>::local_time();
}
};
template <typename time_type>
struct universal_clock_source
{
time_type operator () () const
{
return date_time::microsec_clock<time_type>::universal_time();
}
};
template <typename time_type, typename clock_source_type, typename formater_type>
class custom_clock: public attribute
{
public:
class impl: public attribute::impl
{
public:
attribute_value get_value()
{
auto str = formater_type()( clock_source_type()());
return make_attribute_value( str);
}
};
custom_clock(): attribute( new impl()) {}
explicit custom_clock( const cast_source& source): attribute( source.as<impl>()) {}
};
typedef custom_clock<boost::posix_time::ptime, local_clock_source<boost::posix_time::ptime>, date_time_ms_formatter<boost::posix_time::ptime, '\t'> > local_date_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, universal_clock_source<boost::posix_time::ptime>, date_time_ms_formatter<boost::posix_time::ptime, '\t'> > universal_date_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, local_clock_source<boost::posix_time::ptime>, time_ms_formatter> local_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, universal_clock_source<boost::posix_time::ptime>, time_ms_formatter> universal_time_ms_clock;
}
BOOST_LOG_CLOSE_NAMESPACE // namespace log
}
initialized as
BOOST_LOG_ATTRIBUTE_KEYWORD( dateTimeStamp, "DateTime", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD( timeStamp, "Time", boost::posix_time::ptime)
core->add_global_attribute( dateTimeStamp.get_name(), attrs::local_date_time_ms_clock());
core->add_global_attribute( timeStamp.get_name(), attrs::local_time_ms_clock());
and used as
expr::stream << expr::attr<std::string>( dateTimeStamp.get_name())
expr::stream << expr::attr<std::string>( timeStamp.get_name())
Boost.DateTime (upon which Boost.Log relies) doesn't seem to support specialized fractional seconds formatting, so the only way to do that would be to write your own custom attribute formatter, or (the easier, but less nice way) to slightly modify your formatting code.
Instead of something like this:
backend->set_formatter
(
fmt::stream <<
fmt::date_time<boost::posix_time::ptime>
("TimeStamp", keywords::format = "%Y-%m-%d %H:%M:%S.%f"));
backend->set_formatter
(
fmt::stream <<
fmt::date_time<boost::posix_time::ptime>
("TimeStamp", keywords::format = %Y-%m-%d %H:%M:%S.") <<
(fmt::format("%.2s") % fmt::date_time<boost::posix_time::ptime>("%f"))
);
I haven't tested it myself, but I believe it should work: the first fmt::date_time() will return the timestamp without the fractional seconds, while the second fmt::date_time() will return just the fractional seconds, which will be cut to two digits by the fmt::format().
We addressed it with this class:
class TimeStamp : public boost::log::attributes::local_clock {
public:
typedef boost::log::attribute_value attribute_type;
typedef boost::log::attributes::local_time_traits TimeTraitsT;
typedef TimeTraitsT::time_type time_type;
typedef boost::log::attributes::basic_attribute_value< std::string > result_value;
public:
boost::shared_ptr< attribute_type > get_value() {
time_type posix_time = boost::date_time::microsec_clock< time_type >::universal_time();
time_type::time_duration_type time = posix_time.time_of_day();
time_type::date_type date = posix_time.date();
std::stringstream formatter;
formatter
<< date.year() << "-"
<< std::setfill('0') << std::setw(2) << int(date.month()) << "-"
<< std::setfill('0') << std::setw(2) << date.day() << " "
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.hours()) << ":"
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.minutes()) << ":"
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.seconds()) << ","
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.fractional_seconds()) / 1000
;
return boost::make_shared< result_value >(formatter.str());
}
};
Initialized like this:
boost::log::core::get()->add_global_attribute("TimeStamp", boost::make_shared< TimeStamp >());
And used like this:
backend_ptr->set_formatter(
boost::log::formatters::stream
<< boost::log::formatters::attr< std::string >("TimeStamp")
<< boost::log::formatters::message();
The class, obviously, lets us access or format any portion of the date we wish
Try this one. It works for me under Linux.
sink->set_formatter(log_expr::format("%1%") % log_expr::max_size_decor<char>(22)[log_expr::stream << log_expr::format_date_time<boost::posix_time::ptime>("Timestamp", "%Y-%m-%d %H:%M:%S.%f")]);

Resources