How to "add" user-defined format flags to basic_ostream? - c++

I want to provide a stream operator to output std::chrono::time_point as GMT date, I currently have the following (simplified for ostream only):
using datetime_t = std::chrono::system_clock::time_point;
std::ostream& operator<<(std::ostream &out, datetime_t dt) {
auto time = datetime_t::clock::to_time_t(dt);
auto under_sec =
std::chrono::duration_cast<std::chrono::milliseconds>(
dt.time_since_epoch() % std::chrono::seconds{1});
return out << std::put_time(std::gmtime(&time), "%Y-%m-%dT:%H:%M:%S")
<< "." << std::setfill('0') << std::setw(3) << under_sec.count();
}
Usage:
auto time = datetime_t::clock::now();
std::cout << time;
This works, but it forces the user to:
use the hard-coded format;
output milliseconds.
I would like to provide custom stream manipulator that would allow the user to modify both of these, e.g. for the second (assuming a namespace nm containing the manipulator):
std::cout << nm::us << time;
...that would print up to microseconds.
I already know how to create stream manipulators, e.g.:
namespace nm {
std::ios_base& us(std::ios_base &) { /* ... */ }
}
...but I don't know how to "store" the required information for use in the output operator.
Is there a simply way to "store" information in a stream (user-defined format flags?) to use in a later stream operation? Or another way to obtain slightly equivalent behavior?

As you've already discovered in your comments, yes, streams have, iword and pword storage. Not the easiest thing in the world to work with (designed decades ok), but serviceable.
Another option would be to use an already coded library for this such as Howard Hinnant's free, open source, datetime library:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << format("%FT:%T", floor<microseconds>(system_clock::now())) << '\n';
}
With this library the precision of the output is controlled by adjusting the precision of the input (i.e. with time_point_cast or floor).
Sample output:
2017-07-10T:11:46:59.354321

Related

Parse time format "DD/MM/YYYY at hh:mm:ss" & others using std::chrono::from_stream()

I'm currently trying to parse some info about the start time of an experiment as listed in a log file. After reading in the file important info, e.g column titles, start time, time between measurements, is parsed using <regex>.
I'm trying to use the std::chrono::from_stream(...) function to parse a string with the format "DD/MM/YYYY at hh:mm:ss" into a std::chrono::time_point, example of a string:
08/03/2021 at 09:37:25
At the moment I'm attempting this using the following function which attempts to construct a duration from a provided string to parse & a string to parse it with, then converting that to a time_point so I have control over the clock used:
#include <chrono>
#include <string>
#include <sstream>
#include <iostream>
using nano = std::chrono::duration<std::uint64_t, std::nano>;
template <typename Duration>
Duration TimeFormat(const std::string& str,
const std::string& fmt,
const Duration& default_val)
{
Duration dur;
std::stringstream ss{ str };
std::chrono::from_stream(ss, fmt.c_str(), dur);
/*
from_stream sets the failbit of the input stream if it fails to parse
any part of the input format string or if it receives any contradictory
information.
*/
if (ss.good())
{
std::cout << "Successful parse!" << std::endl;
std::cout << dur.count() << std::endl;
return dur;
}
else
{
std::cout << "Failed parse!" << std::endl;
std::cout << dur.count() << std::endl;
return default_val;
}
}
int main()
{
/*
The file is already read in, and regex matches the correct line from the log file and a
format pattern from a related config file.
*/
/*
Two different lines in the log file give:
- str1 = test start time.
- str2 = time between each measurement.
*/
std::string str1("08/03/2021 at 09:37:25"), str2("00:00:05");
std::string fmt1("%d/%m/%Y at %H:%M:%S"), fmt2("%H:%M:%S");
auto test1 = TimeFormat<nano>(str1, fmt1, nano::zero());
/*
--> "Failed parse!" & test1.count() = 14757395258967641292
A little research indicates that this is what VS initializes variables to
in debug mode. If run in release mode test1.count() = 0 in my tests.
*/
auto test2 = TimeFormat<nano>(str2, fmt2, nano::zero());
/*
--> "Failed parse!" & test2.count() = 5000000000 (5 billion nanoseconds)
Chose nanoseconds because it also has to handle windows file times which are measured
relative to 01/01/1601 in hundreds of nanoseconds. Might be worth pointing out.
What's weird is that it fails even though the value it reads is correct.
*/
/*
... Convert to a time_point after this,
e.g auto t1 = std::chrono::time_point<std::chrono::high_resolution_clock, nano>(test1);
*/
}
The MS documentation for from_stream can be found here. With details about different format characters just after the from_stream docs.
ss.is_good() ?
Is that a type-o in your question or an extension in the Visual Studio std::lib?
I'm going to guess it is a type-o and that you meant ss.good()...
The good() member function checks if all state flags are off:
failbit
badbit
eofbit
eofbit in particular often does not mean "error". It simply means that the parsing reached the end of the stream. You are interpreting "end of stream" as a parsing error.
Instead check failbit or badbit. This is most easily done with the fail() member function.
if (!ss.fail())
...
Update
Any idea why it still won't pass the first string though?
I'm not 100% positive if it is a bug in the VS implementation, or a bug in the C++ spec, or a bug in neither. Either way, it wouldn't return what you're expecting.
For me (using the C++20 chrono preview library), the first parse is successful and returns
34645000000000
which if printed out in hh:mm:ss.fffffffff format is:
09:37:25.000000000
That is, only the time-part is contributing to the return value. This is clearly not what you intended. Your first test appears to intend to parse a time_point, not a duration.
Here is a slightly rewritten program that I think will do what you want, parsing a time_point in the first test, and a duration in the second:
#include <chrono>
#include <string>
#include <sstream>
#include <iostream>
using nano = std::chrono::duration<std::uint64_t, std::nano>;
template <typename TimeType>
TimeType TimeFormat(const std::string& str,
const std::string& fmt,
const TimeType& default_val)
{
TimeType dur;
std::stringstream ss{ str };
std::chrono::from_stream(ss, fmt.c_str(), dur);
/*
from_stream sets the failbit of the input stream if it fails to parse
any part of the input format string or if it receives any contradictory
information.
*/
if (!ss.fail())
{
std::cout << "Successful parse!" << std::endl;
std::cout << dur << std::endl;
return dur;
}
else
{
std::cout << "Failed parse!" << std::endl;
std::cout << dur << std::endl;
return default_val;
}
}
int main()
{
std::string str1("08/03/2021 at 09:37:25"), str2("00:00:05");
std::string fmt1("%d/%m/%Y at %H:%M:%S"), fmt2("%H:%M:%S");
auto test1 = TimeFormat(str1, fmt1, std::chrono::sys_time<nano>{});
auto test2 = TimeFormat(str2, fmt2, nano::zero());
}
For me this outputs:
Successful parse!
2021-03-08 09:37:25.000000000
Successful parse!
5000000000ns
If one wanted the output of the first test in terms of nanoseconds since epoch, then one could extract that from the dur time_point variable with dur.time_since_epoch(). This would then output:
1615196245000000000ns

std::time_point from and to std::string

Am trying to replace some boost::gregorian code using c++20 std::chrono, hoping to remove the boost build depedency. Code is reading and writing to json (using nlohmann) so ability to convert dates to and from std::string is critical.
Using g++ 9.3.0 on Ubuntu 20.04. 2 compile-time erorrs, one on std::chrono::parse() and the second on std::put_time()
For error A on std::chrono::parse(), I see here that calendar support (P0355R7), that includes chrono::parse, is not yet available in gcc libstdc++. Anyone know if this is correct or have a link to an ETA for this? or is there something wrong with how I'm calling parse()?
For error B for std::put_time(): since std:put_time() is documented as c++11 feel like I'm missing something silly here. Also find it strange needing to covert through c's time_t and tm. Is there a better way to convert std::chrono::time_point directly to std::string without resorting to c?
#include <chrono>
#include <string>
#include <sstream>
#include <iostream>
int main(int argc, char *argv[]) {
std::chrono::system_clock::time_point myDate;
//Create time point from string
//Ref: https://en.cppreference.com/w/cpp/chrono/parse
std::stringstream ss;
ss << "2020-05-24";
ss >> std::chrono::parse("%Y-%m-%e", myDate); //error A: ‘parse’ is not a member of ‘std::chrono’
//Write time point to string
//https://en.cppreference.com/w/cpp/io/manip/put_time
//http://cgi.cse.unsw.edu.au/~cs6771/cppreference/en/cpp/chrono/time_point.html
std::string dateString;
std::time_t dateTime = std::chrono::system_clock::to_time_t(myDate);
std::tm tm = *std::localtime(&dateTime);
dateString = std::put_time(&tm, "%Y-%m-%e"); //error B: ‘put_time’ is not a member of ‘std’
//Write out
std::cout << "date: " << dateString << "\n";
return 0;
}
C++20 <chrono> is still under construction for gcc. I've seen no public ETA's for it.
Your syntax for std::chrono::parse looks correct. If you're willing to use a free, open-source, header-only preview of C++20 <chrono> then you can get it to work by adding #include "date/date.h" and using date::parse instead.
Note that the resulting myDate will be 2020-05-24 00:00:00 UTC.
std::put_time lives in the header <iomanip> and is a manipulator. After adding that header and <iostream> you would use it like this:
std::cout << "date: " << std::put_time(&tm, "%Y-%m-%e") << '\n';
If you need the output in a std::string, you will have to stream the manipulator to a std::stringstream first.
C++20 <chrono> will provide an alternative to the C API for formatting:
std::cout << "date: " << std::format("{%Y-%m-%e}", myDate) << '\n';
The preview library also provides this with a slightly altered format string:
std::cout << "date: " << date::format("%Y-%m-%e", myDate) << '\n';

How to check that timezone exists with boost locale

I need to parse time from string (%Y-%M-%d %H:%m:%s) according to some timezone.
My first idea was to try boost::date_time, however it looks like its database is outdated and timezone detection algorithm is wrong in general. So I decided to try boost::locale. It has ICU backend, so timezone support should be good. I use the following code:
namespace as = boost::locale::as;
void foo(std::string time, std::string timezone) {
auto glob = boost::locale::localization_backend_manager::global();
glob.select("icu"); // select icu backend
boost::locale::generator gen{glob};
auto loc = gen.generate(""); // generate locale with boost facets
auto cal = boost::locale::calendar{loc, timezone};
boost::locale::date_time dt{cal};
std::stringstream ss{time};
ss.imbue(loc);
std::cout.imbue(loc);
ss >> as::ftime("%Y-%m-%d %T") >> as::time_zone(timezone) >> dt;
std::cout << as::time_zone("UTC") << dt << std::endl;
std::cout << as::time_zone(timezone) << dt << std::endl;
}
This works well, however if I pass some invalid timezone name ("foo"), the library accepts it, no exception is thrown, the time is parsed as if it is UTC time. That's not good for me, I want to detect this case somehow, so that I can notify user that the result will not be what he/she expects.
My first idea was to check cal.get_time_zone(), but it always returns the string that was passed to constructor ("foo" in my case), no matter if it's valid or not.
Next, I tried to extract calendar_facet from the generated locale, like so:
const auto &icu_cal = std::use_facet<boost::locale::calendar_facet>(loc);
so that I can access an internal abstract_calendar class. Unfortunately, this line doesn't compile. The reason is that boost/locale/generator.hpp has a static constant with the same name (calendar_facet) in the same boost::locale namespace. The compiler reports that it can not instantiate std::use_facet. Maybe I can move it to a separate compilation unit and avoid including generator.hpp header there, but it looks like a hack for me. Is it a bug or I'm missing something here?
Is there a straightforward way how to validate timezone name with boost::locale? Do you recommend it in general? Thanks for your help.
Edit: here is a minimal example of code that doesn't compile for me
#include <boost/locale.hpp>
int main() {
auto my = boost::locale::localization_backend_manager::global();
my.select("icu");
boost::locale::generator gen{my};
std::use_facet<boost::locale::calendar_facet>(gen.generate(""));
return 0;
}
I compile it like so (on ubuntu 16.04, gcc 5.4):
g++ -std=c++14 -L/usr/lib/x86_64-linux-gnu/ test.cpp -lboost_locale -lboost_date_time
Edit 2: With Sehe's help I managed to get calendar facet from locale and now can I check timezone like this:
int main(int argc, char **argv) {
auto my = boost::locale::localization_backend_manager::global();
my.select("icu");
boost::locale::generator gen{my};
auto ptr = std::unique_ptr<boost::locale::abstract_calendar>(std::use_facet<class boost::locale::calendar_facet>(gen.generate("")).create_calendar());
ptr->set_timezone(argv[1]);
// if ICU backend does not recognize timezone, it sets it to Etc/Unknown
if (ptr->get_timezone() != argv[1]) {
std::cout << "bad timezone " << ptr->get_timezone() << std::endl;
} else {
std::cout << "good timezone " << ptr->get_timezone() << std::endl;
}
return 0;
}
Update: while I managed to make boost locale do what I want on linux, I later faced some weird errors when I ported my code to OS X (it looks like mac doesn't have ICU backend by default...). So, I decided to switch to Howard Hinnant's date library instead. This library is of a high quality, works well on both linux and mac, author is helpful and responsive, so highly recommended.
The fix to the non-compiling sample:
Live On Coliru
#include <boost/locale.hpp>
int main() {
auto my = boost::locale::localization_backend_manager::global();
my.select("icu");
boost::locale::generator gen{my};
std::use_facet<class boost::locale::calendar_facet>(gen.generate(""));
}
Here is an alternative timezone library that may be easier to use:
#include "tz.h"
#include <iostream>
#include <sstream>
int
main(int argc, char **argv)
{
try
{
auto tz = date::locate_zone(argv[1]);
std::cout << "good timezone " << tz->name() << std::endl;
date::local_seconds tp;
std::istringstream in{"2017-09-08 11:30:15"};
in >> date::parse("%Y-%m-%d %H:%M:%S", tp);
auto zt = date::make_zoned(tz, tp);
std::cout << date::format("%Y-%m-%d %T %Z which is ", zt);
std::cout << date::format("%Y-%m-%d %T %Z\n", zt.get_sys_time());
}
catch (std::exception const& e)
{
std::cout << "bad timezone " << e.what() << std::endl;
}
}
Sample output 1:
good timezone America/New_York
2017-09-08 11:30:15 EDT which is 2017-09-08 15:30:15 UTC
Sample output 2:
bad timezone America/New_Yor not found in timezone database

C++ convert date formats

I would like to convert an int date like:
20111201
to string:
01DEC2011
Is there a fast date format conversion built into C++ (or maybe a bash system command I can execute instead) to do this or am I stuck making a switch for all of the months?
You could use the strptime to convert your string to a struct tm, then use strftime to reformat it:
#include <ctime>
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream date1;
date1 << 20111201;
struct tm tm;
strptime(date1.str().c_str(), "%Y%m%d", &tm);
char date2[10];
strftime(date2, sizeof(date2), "%d%b%Y", &tm);
std::cout << date1.str() << " -> " << date2 << std::endl;
}
Output is:
20111201 -> 01Dec2011
Just need to convert the Dec to upper case if it's necessary.
Don't use bash here. The way to go is to use Boost in C++ for more reasons than I've time to list here, but ultimately it will be just as fast as most other solutions you'll encounter and unless your functionality is absolutely time critical, it won't make a great deal of difference anyway.
Also, It's going to be far more flexible and maintainable than all those crappy little hard coded date conversion routines that you always encounter.
The following code will do what you want.
#include <iostream>
#include <sstream>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost::gregorian;
using namespace std;
int main(int argc, char **argv)
{
int dateIn = 20111201;
// Read the date in from ISO format as an int.
ostringstream ss;
ss << dateIn;
date d(from_undelimited_string( ss.str() ));
// Set the output format
date_facet *fct = new date_facet("%d%b%Y"); // [1]
locale loc = locale(locale::classic(), fct);
// Render the date as a string;
ss.str("");
ss.imbue(loc);
ss << d;
string dateOut( ss.str() );
boost::to_upper( dateOut );
cout << dateOut << endl;
}
This gives the following output:
01DEC2011
Just changing the format string "%d%b%Y" at ref [1] will change to a different output format but remember I've converted it to uppercase as well.
There's nothing directly built-in, since this format for dates
is relatively rare. The simplest solution here would be to
break the date up into year month day using % and /
operators (e.g. month is value / 100 % 100), then format the
three values normally, using std::ostream, and looking up the
date in a table. (This would obviously require some error
checking, since not all integral values yield valid dates.)
New answer to old question. This answer traffics through the C++11/14 <chrono> library instead of C's tm or boost::date_time. Otherwise it is very similar to the existing answers. It requires this free, open-source library for the parsing and formatting.
#include "tz.h"
#include <iostream>
#include <locale>
#include <sstream>
int
main()
{
auto date1 = 20111201;
std::stringstream stream;
stream.exceptions(std::ios::failbit);
stream << date1;
std::chrono::system_clock::time_point tp;
date::parse(stream, "%Y%m%d", tp);
auto str = date::format("%d%b%Y", tp);
auto& ct = std::use_facet<std::ctype<char>>(std::locale::classic());
ct.toupper(&str.front(), &str.back()+1);
std::cout << str << '\n';
}
I've included stream.exceptions(std::ios::failbit); to noisily detect invalid "integer dates". And I've included old C++98 code to convert the string to uppercase (the locale dance at the end).
01DEC2011
One of the advantages of using a modern C++ date/time library is the ease with which changes can be made. For example, what if now you need to parse the timestamp not with day-precision, but with millisecond precision? Here is how that might be done:
auto date1 = 20111201093357.275L;
std::stringstream stream;
stream.exceptions(std::ios::failbit);
stream << std::fixed << date1;
std::chrono::system_clock::time_point tp;
date::parse(stream, "%Y%m%d%H%M%S", tp);
auto str = date::format("%d%b%Y %T", tp);
auto& ct = std::use_facet<std::ctype<char>>(std::locale::classic());
ct.toupper(&str.front(), &str.back()+1);
std::cout << str << '\n';
which outputs:
01DEC2011 09:33:57.275000
Or perhaps these timestamps are known to originate from Chatham Island off the coast of New Zealand and you need them in UTC. Just add one line after the parse:
tp = date::locate_zone("Pacific/Chatham")->to_sys(tp);
And now the output is:
30NOV2011 19:48:57.275000
Taking into account arbitrary timezones and subsecond precision is currently beyond the capabilities of all other C++ libraries.

"Roll-Back" or Undo Any Manipulators Applied To A Stream Without Knowing What The Manipulators Were [duplicate]

This question already has answers here:
Restore the state of std::cout after manipulating it
(9 answers)
Closed 4 years ago.
If I apply an arbitrary number of manipulators to a stream, is there a way to undo the application of those manipulators in a generic way?
For example, consider the following:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "Hello" << hex << 42 << "\n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know
// what modifiers I added to it
// ... MAGIC HAPPENS! ...
cout << "This should not be in hex: " << 42 << "\n";
}
Suppose I want to add code at MAGIC HAPPENS that will revert the state of the stream manipulators to whatever it was before I did cout << hex. But I don't know what manipulators I added. How can I accomplish this?
In other words, I'd like to be able to write something like this (psudocode/fantasy code):
std::something old_state = cout.current_manip_state();
cout << hex;
cout.restore_manip_state(old_state);
Is this possible?
EDIT:
In case you're curious, I'm interested in doing this in a custom operator<<() I'm writing for a complex type. The type is a kind of discriminated union, and different value types will have different manips applied to the stream.
EDIT2:
Restriction: I cannot use Boost or any other 3rd party libraries. Solution must be in standard C++.
Yes.
You can save the state and restore it:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
std::ios state(NULL);
state.copyfmt(std::cout);
cout << "Hello" << hex << 42 << "\n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know what modifiers I added to it
// ... MAGIC HAPPENS! ...
std::cout.copyfmt(state);
cout << "This should not be in hex: " << 42 << "\n";
}
If you want to get back to the default state you don't even need to save the state you can extract it from a temporary object.
std::cout.copyfmt(std::ios(NULL));
The standard manipulators all manipulate a stream's format flags, precision and width settings. The width setting is reset by most formatted output operations anyway. These can all be retrieved like this:
std::ios_base::fmtflags saveflags = std::cout.flags();
std::streamsize prec = std::cout.precision();
std::streamsize width = std::cout.width();
and restored:
std::cout.flags( saveflags );
std::cout.precision( prec );
std::cout.width( width );
Turning this into an RAII class is an exercise for the reader...
Saving and restoring state is not exception-safe. I would propose to shuffle everything into a stringstream, and finally you put that on the real stream (which has never changed its flags at all).
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::ostringstream out;
out << "Hello" << std::hex << 42 << "\n";
std::cout << out.str();
// no magic necessary!
std::cout << "This should not be in hex: " << 42 << "\n";
}
Of course this is a little less performant. The perfect solutions depends on your specific needs.
Boost IO State saver might be of help.
http://www.boost.org/doc/libs/1_40_0/libs/io/doc/ios_state.html
I know that is an old question, but for future generations:
You can also write a simple state saver yourself (it will certainly help you avoid leaving the state changed). Just use the solution suggested by #loki and run it from the constructor/destructor of an object (in short: RAII) along these lines:
class stateSaver
{
public:
stateSaver(ostream& os): stream_(os), state_(nullptr) { state_.copyfmt(os); }
~stateSaver() { stream_.copyfmt(state_); }
private:
std::ios state_;
ostream& stream_;
};
Then, you will use it like this:
void myFunc() {
stateSaver state(cout);
cout << hex << 42 << endl; // will be in hex
}
int main() {
cout << 42 << endl; // will be in dec
myFunc();
cout << 42 << endl; // will also be in dec
}