How to convert a boost::ptime to string - c++

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

Related

Why does get_time fail to parse what put_time produces?

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?

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';

Time stamp for saving file or folder?

Is there a simpler way to do a time stamp for saving a file/creating a directory as a date time stamp ?
only using standard library (not boost). Is there a faster way to do it ?
This is my current code
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t(now);
tm utc_tm = *gmtime(&tt);
oname.str("");
oname << (utc_tm.tm_year + 1900) << '-' << std::setfill('0') << std::setw(2) << (utc_tm.tm_mon + 1) << '-' << std::setfill('0') << std::setw(2) << utc_tm.tm_mday << " " << std::setfill('0') << std::setw(2)<< utc_tm.tm_hour <<':' << std::setfill('0') << std::setw(2) << utc_tm.tm_min <<':' << std::setfill('0') << std::setw(2) << utc_tm.tm_sec;
ts = oname.str();
There is a less tortuous way:
#include <string>
#include <ctime>
std::string get_timestamp()
{
auto now = std::time(nullptr);
char buf[sizeof("YYYY-MM-DD HH:MM:SS")];
return std::string(buf,buf +
std::strftime(buf,sizeof(buf),"%F %T",std::gmtime(&now)));
}
It is very probably also faster, because it is less tortuous, but that is
also very probably immaterial in a setting where disc I/O is in play.
This gives you the same timestamps as your own code, e.g.
2015-03-28 10:48:45
See std::time and
std::strftime to
understand how the desired formatting is achieved and note that std::strftime
returns the length of the string it has composed, excluding its nul-terminator.
This code is standard, but if you are working with MS VC++ 2013 or later then
you could also consider the use of std::put_time,
as in:
#include <iomanip>
#include <sstream>
#include <string>
#include <ctime>
std::string get_timestamp()
{
auto now = std::time(nullptr);
std::ostringstream os;
os << std::put_time(std::gmtime(&now),"%F %T");
return os.str();
}
which is simpler still. (I have not tested that.) std::put_time however
is unsupported by gcc as of 4.9.
Seemingly you want your timestamps formatted as YYYY-MM-DD HH:MM:SS. If they
are to be used in filenames, it would be more prudent to keep them free of spaces:
perhaps YYYY-MM-DD_HH:MM:SS.

How to print a bunch of integers with the same formatting?

I would like to print a bunch of integers on 2 fields with '0' as fill character. I can do it but it leads to code duplication. How should I change the code so that the code duplication can be factored out?
#include <ctime>
#include <sstream>
#include <iomanip>
#include <iostream>
using namespace std;
string timestamp() {
time_t now = time(0);
tm t = *localtime(&now);
ostringstream ss;
t.tm_mday = 9; // cheat a little to test it
t.tm_hour = 8;
ss << (t.tm_year+1900)
<< setw(2) << setfill('0') << (t.tm_mon+1) // Code duplication
<< setw(2) << setfill('0') << t.tm_mday
<< setw(2) << setfill('0') << t.tm_hour
<< setw(2) << setfill('0') << t.tm_min
<< setw(2) << setfill('0') << t.tm_sec;
return ss.str();
}
int main() {
cout << timestamp() << endl;
return 0;
}
I have tried
std::ostream& operator<<(std::ostream& s, int i) {
return s << std::setw(2) << std::setfill('0') << i;
}
but it did not work, the operator<< calls are ambigous.
EDIT I got 4 awesome answers and I picked the one that is perhaps the simplest and the most generic one (that is, doesn't assume that we are dealing with timestamps). For the actual problem, I will probably use std::put_time or strftime though.
In C++20 you'll be able to do this with std::format in a less verbose way:
ss << std::format("{}{:02}{:02}{:02}{:02}{:02}",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec);
and it's even easier with the {fmt} library that supports tm formatting directly:
auto s = fmt::format("{:%Y%m%d%H%M%S}", t);
You need a proxy for your string stream like this:
struct stream{
std::ostringstream ss;
stream& operator<<(int i){
ss << std::setw(2) << std::setfill('0') << i;
return *this; // See Note below
}
};
Then your formatting code will just be this:
stream ss;
ss << (t.tm_year+1900)
<< (t.tm_mon+1)
<< t.tm_mday
<< t.tm_hour
<< t.tm_min
<< t.tm_sec;
return ss.ss.str();
ps. Note the general format of my stream::operator<<() which does its work first, then returns something.
The "obvious" solution is to use a manipulator to install a custom std::num_put<char> facet which just formats ints as desired.
The above statement may be a bit cryptic although it entirely describes the solution. Below is the code to actually implement the logic. The first ingredient is a special std::num_put<char> facet which is just a class derived from std::num_put<char> and overriding one of its virtual functions. The used facet is a filtering facet which looks at a flag stored with the stream (using iword()) to determine whether it should change the behavior or not. Here is the code:
class num_put
: public std::num_put<char>
{
std::locale loc_;
static int index() {
static int rc(std::ios_base::xalloc());
return rc;
}
friend std::ostream& twodigits(std::ostream&);
friend std::ostream& notwodigits(std::ostream&);
public:
num_put(std::locale loc): loc_(loc) {}
iter_type do_put(iter_type to, std::ios_base& fmt,
char fill, long value) const {
if (fmt.iword(index())) {
fmt.width(2);
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, '0', value);
}
else {
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, fill, value);
}
}
};
The main part is the do_put() member function which decides how the value needs to be formatted: If the flag in fmt.iword(index()) is non-zero, it sets the width to 2 and calls the formatting function with a fill character of 0. The width is going to be reset anyway and the fill character doesn't get stored with the stream, i.e., there is no need for any clean-up.
Normally, the code would probably live in a separate translation unit and it wouldn't be declared in a header. The only functions really declared in a header would be twodigits() and notwodigits() which are made friends in this case to provide access to the index() member function. The index() member function just allocates an index usable with std::ios_base::iword() when called the time and it then just returns this index. The manipulators twodigits() and notwodigits() primarily set this index. If the num_put facet isn't installed for the stream twodigits() also installs the facet:
std::ostream& twodigits(std::ostream& out)
{
if (!dynamic_cast<num_put const*>(
&std::use_facet<std::num_put<char> >(out.getloc()))) {
out.imbue(std::locale(out.getloc(), new num_put(out.getloc())));
}
out.iword(num_put::index()) = true;
return out;
}
std::ostream& notwodigits(std::ostream& out)
{
out.iword(num_put::index()) = false;
return out;
}
The twodigits() manipulator allocates the num_put facet using new num_put(out.getloc()). It doesn't require any clean-up because installing a facet in a std::locale object does the necessary clean-up. The original std::locale of the stream is accessed using out.getloc(). It is changed by the facet. In theory the notwodigits could restore the original std::locale instead of using a flag. However, imbue() can be a relatively expensive operation and using a flag should be a lot cheaper. Of course, if there are lots of similar formatting flags, things may become different...
To demonstrate the use of the manipulators there is a simple test program below. It sets up the formatting flag twodigits twice to verify that facet is only created once (it would be a bit silly to create a chain of std::locales to pass through the formatting:
int main()
{
std::cout << "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits1='" << 1 << "' "
<< "two-digits2='" << 2 << "' "
<< "two-digits3='" << 3 << "' "
<< notwodigits << '\n'
<< "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits4='" << 4 << "' "
<< '\n';
}
Besides formatting integers with std::setw / std::setfill or ios_base::width / basic_ios::fill, if you want to format a date/time object you may want to consider using std::put_time / std::gettime
For convenient output formatting you may use boost::format() with sprintf-like formatting options:
#include <boost/format.hpp>
#include <iostream>
int main() {
int i1 = 1, i2 = 10, i3 = 100;
std::cout << boost::format("%03i %03i %03i\n") % i1 % i2 % i3;
// output is: 001 010 100
}
Little code duplication, additional implementation effort is marginal.
If all you want to do is output formatting of your timestamp, you should obviously use strftime(). That's what it's made for:
#include <ctime>
#include <iostream>
std::string timestamp() {
char buf[20];
const char fmt[] = "%Y%m%d%H%M%S";
time_t now = time(0);
strftime(buf, sizeof(buf), fmt, localtime(&now));
return buf;
}
int main() {
std::cout << timestamp() << std::endl;
}
operator<<(std::ostream& s, int i) is "ambiguous" because such a function already exists.
All you need to do is give that function a signature that doesn't conflict.

converting a timestring to a duration

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
}