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.
Related
How do I get a uint unix timestamp in C++? I've googled a bit and it seems that most methods are looking for more convoluted ways to represent time. Can't I just get it as a uint?
C++20 introduced a guarantee that time_since_epoch is relative to the UNIX epoch, and cppreference.com gives an example that I've distilled to the relevant code, and changed to units of seconds rather than hours:
#include <iostream>
#include <chrono>
int main()
{
const auto p1 = std::chrono::system_clock::now();
std::cout << "seconds since epoch: "
<< std::chrono::duration_cast<std::chrono::seconds>(
p1.time_since_epoch()).count() << '\n';
}
Using C++17 or earlier, time() is the simplest function - seconds since Epoch, which for Linux and UNIX at least would be the UNIX epoch. Linux manpage here.
The cppreference page linked above gives this example:
#include <ctime>
#include <iostream>
int main()
{
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result))
<< result << " seconds since the Epoch\n";
}
#include<iostream>
#include<ctime>
int main()
{
std::time_t t = std::time(0); // t is an integer type
std::cout << t << " seconds since 01-Jan-1970\n";
return 0;
}
The most common advice is wrong, you can't just rely on time(). That's used for relative timing: ISO C++ doesn't specify that 1970-01-01T00:00Z is time_t(0)
What's worse is that you can't easily figure it out, either. Sure, you can find the calendar date of time_t(0) with gmtime, but what are you going to do if that's 2000-01-01T00:00Z ? How many seconds were there between 1970-01-01T00:00Z and 2000-01-01T00:00Z? It's certainly no multiple of 60, due to leap seconds.
As this is the first result on google and there's no C++20 answer yet, here's how to use std::chrono to do this:
#include <chrono>
//...
using namespace std::chrono;
int64_t timestamp = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
In versions of C++ before 20, system_clock's epoch being Unix epoch is a de-facto convention, but it's not standardized. If you're not on C++20, use at your own risk.
#include <iostream>
#include <sys/time.h>
using namespace std;
int main ()
{
unsigned long int sec= time(NULL);
cout<<sec<<endl;
}
I created a global define with more information:
#include <iostream>
#include <ctime>
#include <iomanip>
#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) // only show filename and not it's path (less clutter)
#define INFO std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [INFO] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
#define ERROR std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [ERROR] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
static std::time_t time_now = std::time(nullptr);
Use it like this:
INFO << "Hello world" << std::endl;
ERROR << "Goodbye world" << std::endl;
Sample output:
16-06-23 21:33:19 [INFO] main.cpp(main:6) >> Hello world
16-06-23 21:33:19 [ERROR] main.cpp(main:7) >> Goodbye world
Put these lines in your header file. I find this very useful for debugging, etc.
Windows uses a different epoch and time units: see
Convert Windows Filetime to second in Unix/Linux
What std::time() returns on Windows is (as yet) unknown to me (;-))
What's a standard way to get a date time in ISO8601 format on Windows using C++? Specifically, I would like it to be formatted as:
2017-02-22T10:00:00.123-05:00
2017-02-22T10:00:00.123 >>> -05:00 <<< # how to print the offset?
I was looking into combining the output of GetLocalTime and GetTimeZoneInformation, but this looks esoteric. There are similar questions on SO, however, I've not found a single one that prints UTC offset in a desired format. Is there a better approach?
The format specifier %z gives you the timezone offset as described in the documentation (e.g. MSDN on strftime) but lefts out the ':'. You can use it like this to get the ':' into your string:
struct tm tmNow;
time_t now = time(NULL); // Get the current time
_localtime64_s(&tmNow, &now);
char bufferTime[26];
char bufferTimezoneOffset[6];
size_t tsizTime = strftime(bufferTime, 26, "%Y-%m-%dT%H:%M:%S", &tmNow); // The current time formatted "2017-02-22T10:00:00"
size_t tsizOffset = strftime(bufferTimezoneOffset, 6, "%z", &tmNow); // The timezone offset -0500
strncpy_s(&bufferTime[tsizTime], 26, bufferTimezoneOffset, 3); // Adds the hour part of the timezone offset
bufferTime[tsizTime + 3] = ':'; // insert ':'
strncpy_s(&bufferTime[tsizTime + 4], 26, &bufferTimezoneOffset[3], 3); // Adds the minutes part of the timezone offset
puts(bufferTime); // Your output: "2017-02-22T10:00:00-05:00"
I left out the milliseconds, as they are not part of the localtime as far as I know.
Maybe something like this. We call GetLocalTime and GetTimeZoneInformation then pass it to the function which returns formatted string.
This is written quickly, not tested besides observing the fact it returns correct result on my machine now. It operates on the fact that SYSTEMTIME has a member Bias where UTC = Localtime + Bias and Bias is set in minutes. So get hours by dividing by 60 and taking absolute value of that. Then we get the minutes in similar way and set the sign depending on if Bias > 0
#include <Windows.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
std::string format_system_time(const SYSTEMTIME& sys_time, const TIME_ZONE_INFORMATION& time_zone)
{
std::ostringstream formatted_date_time;
formatted_date_time << std::setfill('0');
formatted_date_time << sys_time.wYear << "-" << std::setw(2) << sys_time.wMonth << "-" <<
std::setw(2) << sys_time.wDay << "T" << std::setw(2) << sys_time.wHour << ":" <<
std::setw(2) << sys_time.wMinute << ":" << std::setw(2) << sys_time.wSecond << "." <<
std::setw(3) << sys_time.wMilliseconds;
//UTC = localtime + bias; bias is in minutes
int utc_offset_hours = time_zone.Bias / 60;
int utc_offset_minutes = std::abs(time_zone.Bias - (utc_offset_hours * 60));
char offset_sign = time_zone.Bias > 0 ? '-' : '+';
formatted_date_time << offset_sign << std::setw(2) << std::abs(utc_offset_hours) << ":" << utc_offset_minutes;
return formatted_date_time.str();
}
int main(int argc, char* argv[])
{
SYSTEMTIME date_and_time;
GetLocalTime(&date_and_time);
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
auto& formatted_date_time = format_system_time(date_and_time, time_zone);
return 0;
}
I don't think there is a drop-in solution for c++ on Windows. The closest you can get is InternetTimeFromSystemTime but it is only documented to support RFC1123.
You probably have to code it yourself with GetLocalTime + GetTimeZoneInformation + wsprintf (or GetTimeZoneInformationForYear if you are not dealing with the current time).
Using Howard Hinnant's free, open-source timezone library, which works on VS-2013 and later, but does require some installation:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
cout << format("%FT%T%Ez\n", zt);
}
This just output for me:
2017-02-22T17:29:03.859-05:00
I currently have a log process in boost
that is initialized with
keywords::file_name = (my_file_str + %Y-%m-%d_%H.%5N.log).c_str();
Is there any way to change the timezone of the datetime object? I would like to use a timezone that rolls at 5PM US/New_York namely EST-2EDT.
Yes, it is possible, here is a function generating a timestamp in US/NY:
#include <boost/date_time/local_time/local_time.hpp>
#include <sstream>
std::string getNYCTimestamp() {
boost::posix_time::ptime pt =
boost::posix_time::microsec_clock::universal_time();
boost::local_time::time_zone_ptr utc_zone(
new boost::local_time::posix_time_zone("UTC"));
boost::local_time::local_date_time utc_time(pt, utc_zone);
boost::local_time::time_zone_ptr nyc_zone(
new boost::local_time::posix_time_zone("EST-05:00:00EDT+01:00:00,M4.1.0/02:00:00,M10.5.0/02:00:00"));
boost::local_time::local_date_time nyc_time = utc_time.local_time_in(nyc_zone);
auto our_facet = new boost::gregorian::date_facet("%Y-%m-%d");
our_facet->format("%Y-%m-%d");
auto os = std::ostringstream();
os.imbue(std::locale(std::locale::classic(), our_facet));
boost::posix_time::time_duration t = nyc_time.time_of_day();
os << nyc_time.date() << "_"
<< std::setw(2) << std::setfill('0') << t.hours() << '-'
<< std::setw(2) << std::setfill('0') << t.minutes() << '-'
<< std::setw(2) << std::setfill('0') << t.seconds() << '.'
<< std::setw(6) << std::setfill('0') << t.fractional_seconds();
return os.str();
}
Note, that "%Y-%m-%d_%H.%5N" is most probably wrong, because:
it omits minutes and seconds
it tries to fit nanoseconds (9 digits) into 5 symbols.
I am not 100% sure this will suffice (since I don't know what your requirements are) but here : http://boost-log.sourceforge.net/libs/log/doc/html/log/tutorial/attributes.html is a discussion of log attributes. It seems to me that you may be able to add it a secondary timestamp that is adjusted fo timezone.
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
I'm new to std::chrono and I'm looking for a simple way to construct a string containing a time interval formatted hhh:mm:ss (yes, 3 hour figures), indicating the difference between a start time point and now.
How would I go about this using a steady_clock? The examples on Cppreference don't quite fit this problem.
Any time you find yourself manually applying conversion factors among units with the <chrono> library, you should be asking yourself:
Why am I converting units manually? Isn't this what <chrono> is
supposed to do for me?!
A "conversion factor" is 60, or 1000, or 100, or whatever. If you see it in your code, you're opening yourself up to conversion factor errors.
Here is sasha.sochka's code rewritten without these conversion factors. And just to throw in how general this technique is, milliseconds are added for flare:
#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>
int main() {
using namespace std::chrono;
steady_clock::time_point start;
steady_clock::time_point now = steady_clock::now();
auto d = now -start;
auto hhh = duration_cast<hours>(d);
d -= hhh;
auto mm = duration_cast<minutes>(d);
d -= mm;
auto ss = duration_cast<seconds>(d);
d -= ss;
auto ms = duration_cast<milliseconds>(d);
std::ostringstream stream;
stream << std::setfill('0') << std::setw(3) << hhh.count() << ':' <<
std::setfill('0') << std::setw(2) << mm.count() << ':' <<
std::setfill('0') << std::setw(2) << ss.count() << '.' <<
std::setfill('0') << std::setw(3) << ms.count();
std::string result = stream.str();
std::cout << result << '\n';
}
There are other ways to do this without exposed conversion factors, this way is only an example. My main point is: avoid hardcoding unit conversion factors in your code. They are error prone. Even if you get it right when you first code it, conversion factors are vulnerable to future code maintenance. You can future-proof your code by demanding that all unit conversions happen within the <chrono> library.
As Joachim Pileborg noted higher in the comments there is no function for format a string from a duration object. But you can do it using duration_cast to convert time difference first to hours and then minutes and seconds.
After that using C++11 to_string function you can concatenate them to get the resulting string.
#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>
int main() {
using namespace std::chrono;
steady_clock::time_point start = /* Some point in time */;
steady_clock::time_point now = steady_clock::now();
int hhh = duration_cast<hours>(now - start).count();
int mm = duration_cast<minutes>(now - start).count() % 60;
int ss = duration_cast<seconds>(now - start).count() % 60;
std::ostringstream stream;
stream << std::setfill('0') << std::setw(3) << hhh << ':' <<
std::setfill('0') << std::setw(2) << mm << ':' <<
std::setfill('0') << std::setw(2) << ss;
std::string result = stream.str();
}