At the moment I am trying to read in a timestring formatted and create a duration from that. I am currently trying to use the boost date_time time_duration class to read and store the value.
boost date_time provides a method time_duration duration_from_string(std::string) that allows a time_duration to be created from a time string and it accepts strings formatted appropriately ("[-]h[h][:mm][:ss][.fff]".).
Now this method works fine if you use a correctly formatted time string. However if you submit something invalid like "ham_sandwich" or "100" then you will instead be returned a time_duration that is not valid. Specifically if you try to pass it to a standard output stream then an assertion will occur.
My question is: Does anyone know how to test the validity of the boost time_duration? and failing that can you suggest another method of reading a timestring and getting a duration from it?
Note: I have tried the obvious testing methods that time_duration provides; is_not_a_date_time(), is_special() etc and they don't pick up that there is an issue.
Using boost 1.38.0
From the documentation, it looks like you may want to try using the stream operators (operator<<, operator>>); error conditions are described at Date Time Input/Output.
Alternately, I suppose you could validate the string before passing it in. Right offhand, it doesn't look like that particular method has any error handling.
Edit:
I'm not sure I would have thought to check the return value like this if it weren't for Brian's answer, but for completeness here's a full example that takes a string as input. You can either check the return value or have it throw an exception (I believe you'd want to catch std::ios_base_failure):
#include <iostream>
#include <sstream>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace std;
using namespace boost::posix_time;
int main(int argc, char **argv) {
if (argc < 2) {
cout << "Usage: " << argv[0] << " TIME_DURATION" << endl;
return 2;
}
// No exception
stringstream ss_noexcept(argv[1]);
time_duration td1;
if (ss_noexcept >> td1) {
cout << "Valid time duration: " << td1 << endl;
} else {
cout << "Invalid time duration." << endl;
}
// Throws exception
stringstream ss2;
time_duration td2;
ss2.exceptions(ios_base::failbit);
ss2.str(argv[1]);
try {
ss2 >> td2;
cout << "Time duration: " << td2 << endl;
} catch (ios_base::failure e) {
cout << "Invalid time duration (exception caught). what():\n"
<< e.what() << endl;
}
}
Use the stream operators.
time_duration td;
if (std::cin >> td)
{
// it's valid
}
else
{
// it isn't valid
}
Related
I am getting incorrect results using get_time to parse a date with a PM modifier.
To be sure that I am using the correct modifier (even though it should not depend on the locale at all), I generate the time using put_time in this example code:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main() {
// Initialize time from 24-format
tm tm;
strptime("16:33:45", "%H:%M:%S", &tm);
// Define 12h time format
string fmt("%I:%M:%S%p");
// Convert time to 12h format and print - looks good!
ostringstream oss;
oss << put_time(&tm, fmt.c_str());
cout << oss.str() << endl;
// Read time in 12h format
istringstream iss(oss.str());
iss >> get_time(&tm, fmt.c_str());
// Result is wrong!
cout << iss.fail() << " (Fail)" << endl;
cout << tm.tm_hour << endl;
// Read time in 12h format using strptime
strptime(iss.str().c_str(), fmt.c_str(), &tm);
// Result is correct!
cout << "Correct" << endl;
cout << tm.tm_hour << endl;
}
Output:
04:33:45PM
1 (Fail)
4
Correct
16
See also https://coliru.stacked-crooked.com/view?id=c4f75f14fdf53095
I have come across an (unconfirmed) GCC bug from 2018 which reads very similarly, namely, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84216. Also, I have found is this a bug in std::get_time? which according to the only answer is related to some Microsoft implementation I am not aware of using.
strptime is able to parse the time correctly.
Is this a bug somewhere, or am I using get_time incorrectly?
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
I would like to be able to catch different logic_errors and be able to differentiate them. Can I somehow pass additional parameters to the logical error which to catch later. The idea is that I need to print. Right now I am just catching the default errors that stof can return.
"Sorry invalid temperature" or "Sorry invalid rainfall"
P.S. The function stringToTime converts dates to strings and throws logic error with some text, if the date doesn't match certain criteria. Thank you!
try{
tm date = stringToTime(year);
float temp = stof(temperature);
float rain = stof(rainfall);
}
catch(logic_error e){
if( string(e.what()) == "stof"){
cout << "Sorry wrong arguments for either Temperature or Rainfall" << endl;
}else{
cout << e.what() << endl;
}
}
what() text is implementation defined, and GCC only does lazy (but efficient) printing like that. But you can split the extraction into two functions:
float getTemperature(const std::string& temperature) {
try{
return std::stof(temperature);
}
catch(std::logic_error& e){
std::cout << "Sorry wrong argument for Temperature" << std::endl;
throw e; //or you can throw a different exception
}
}
//same for getRainfall()
void validateArguments()
{
try {
tm date = stringToTime(year);
float temp = getTemperature(temperature);
float rain = getRainfall(rainfall);
} catch (std::logic_error& e) {
if( string(e.what()) == "stof"){
//no need to print anymore, but you can e.g. ask for arguments again or something
}else{
cout << e.what() << endl;
}
}
Side note: Consider using your own exception class for throwing from stringToTime (it can be derived from std::logic_error if you prefer, or straight from std::exception). It's safer and compiler-independent way to distinguish different exceptions. Leave exceptions from standard library to standard library.
Pass in parameters as part of the logic_error constructor. As below in the HERE! comment.
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
// From: https://stackoverflow.com/questions/61941722/differentiate-logic-error-in-c
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
tm stringToTime( string input )
{
tm retval;
retval.tm_year = stof( input ) - 1990;
logic_error e( "stof" ); // HERE! Is the constructor that can differentiate the logic_error->when() value.
throw( e );
return retval;
}
int main()
{
printf("User defined logic_error example.\n");
string year = "2020";
string temperature = "70";
string rainfall = "1";
int lineNum = 10;
string fieldNames[2] = { "temperature", "rainfaill" };
try{
tm date = stringToTime(year);
float temp = stof(temperature);
float rain = stof(rainfall);
}
catch(logic_error e){
if( string( e.what() ) == "stof"){
cout << "Sorry wrong arguments for either Temperature or Rainfall" << endl;
}else{
cout << e.what() << " on line " << lineNum + 1 << " type " << fieldNames[0] << endl;
}
}
return 0;
}
I'm having trouble converting a ptime object from boost into a string to be passed in to a function. I have found multiple similar other threads in regards to outputing a boost time object to a string (mostly to cout) but none of what I've found on them are working.
It appears the easiest way is inserting the ptime object into a stringstream and then using the stringstream's string. I have also attempted to imbue the stringstream with a time_facet, as some of the answers on other threads suggest. However, I am unable to create a time_facet object. It gives me the error that the argument list for the class template is missing. What is confusing is the nowhere on the internet have I found any mention of an argument list for time_facet, and even boost's documentation page shows that the default constructor for a time_facet is merely time_facet().
Below is a simple version of what I have tried:
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
boost::posix_time::ptime time = boost::posix_time::time_from_string("1981-08-20 08:05:00");
std::stringstream sstream;
sstream << time;
_updateStatement->setString(1, (sql::SQLString)sstream.str());
The insertion of time into the stringstream gives me a bunch of compilation errors in the vein of
error C2220: warning treated as error - no 'object' file generated C:\code\trunk\Development\External\boost\include\boost/date_time/time_facet.hpp(247) :while compiling class template member function 'boost::date_time::time_facet<time_type,CharT>::time_facet(size_t)'
with
[
time_type=boost::posix_time::ptime,
CharT=char
]
despite the fact that I haven't used any time_facet objects.
When I DO try to do this with a time_facet object, I add in
sstream.imbue(std::locale(sstream.getloc(), new boost::date_time::time_facet("%Y-%m-%d %H:%M:%S")));
before inserting the time into the stringstream. The errors for that are that it wants an argument list as mentioned at the top of this post.
Is there perhaps a function in boost that is the reverse of boost::posix_time::time_from_string()? If not, any other help would be appreciated. Thank you.
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
My usage using release 1.55
#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int main()
{
boost::gregorian::date dayte(boost::gregorian::day_clock::local_day());
boost::posix_time::ptime midnight(dayte);
boost::posix_time::ptime
now(boost::posix_time::microsec_clock::local_time());
boost::posix_time::time_duration td = now - midnight;
std::stringstream sstream;
std::cout << dayte << std::endl;
std::cout << dayte.year() << "/" << dayte.month().as_number()
<< "/" << dayte.day() << std::endl;
std::cout << now << std::endl;
std::cout << td << std::endl;
std::cout << td.hours() << "/" << td.minutes() << "/"
<< td.seconds() << "/" << td.fractional_seconds() << std::endl;
sstream << dayte << std::endl;
sstream << dayte.year() << "/" << dayte.month().as_number()
<< "/" << dayte.day() << std::endl;
sstream << now << std::endl;
sstream << td << std::endl;
sstream << td.hours() << "/" << td.minutes() << "/" << td.seconds()
<< "/" << td.fractional_seconds() << std::endl;
std::cout << sstream.str();
}
Results:
2015-Oct-27
2015/10/27
2015-Oct-27 14:25:18.614684
14:25:18.614684
14/25/18/614684
2015-Oct-27
2015/10/27
2015-Oct-27 14:25:18.614684
14:25:18.614684
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
}