I want to create a log file with the name mentioning the date and time and I am using Visual Studio 2013(V120). currently I am implemented a code like this but get into issues at run time. Could anyone has a method for this
std::string Logger::GetTimeStampWithMilliSeconds() const
{
const auto now = std::chrono::system_clock::now();
const auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
const auto nowAsTimeT = std::chrono::system_clock::to_time_t(now);
struct tm tm {};
localtime_s(&tm, &nowAsTimeT);
std::stringstream nowSs;
nowSs << std::put_time(&tm, "%Y-%m-%d %T") << '.' << std::setfill('0') << std::setw(3) << nowMs.count();
return nowSs.str();
The issue is replicate below.
Related
I have a backend process running 24*7 mostly built using C++ and I need to validate if an input date (in format YYYYMMDD) belongs in a set of next 5 business days. The input date is not a clear indicator of the current date so I am using the following function to get the current date and then calculating the next 5 business days from it.
const std::string& CurrentDateStr() {
static const std::string sDate = []() {
time_t currTime = time(NULL);
struct tm timeinfo;
localtime_r(&currTime, &timeinfo);
char buffer[16]="";
strftime(buffer, sizeof(buffer), "%Y%m%d", &timeinfo);
return std::string(buffer);
} ();
return sDate;
}
This function returns me the correct current date if the process was started today but if the process continues running till tomorrow then it will return me yesterday's date as current date due to which calculation of next 5 business days from current date goes for a toss.
Is this expected ? Is there some workaround for it or is there a better way to implement the requirement using standard C++
Your issue is the static variable. You should read up on that, because you're going to encounter it a lot. This is what the comments were trying to get you to do. You can fix your issue by just removing it:
const std::string& CurrentDateStr() {
time_t currTime = time(NULL);
struct tm timeinfo;
localtime_r(&currTime, &timeinfo);
char buffer[16]="";
strftime(buffer, sizeof(buffer), "%Y%m%d", &timeinfo);
return std::string(buffer);
}
For a more modern solution, as suggested in the comments as well, read up on chrono. Especially system_clock::now().
one way to do it using chrono:
#include <iostream>
#include <ctime>
#include <chrono>
#include <thread>
int main()
{
while (true)
{
theTime currentTime = time(nullptr);
tm* date = gmtime(¤tTime);
// Print the date and time
std::cout << "Current date and time: " << date->theDay << "/" << date->theMon + 1 << "/" << date->theYear + 1900;
std::cout << " " << date->theHour << ":" << date->theMmin << ":" << date->theSec << std::endl;
// Wait for 1 minute
std::this_thread::sleep_for(std::chrono::minutes(1));
}
}
OR Use the sleep method.
#include <iostream>
#include <ctime>
#include <unistd.h>
int main()
{
while (true)
{
time_t currentTime = time(nullptr);
tm* date = gmtime(¤tTime);
std::cout << "Current date and time: " << date->tm_mday << "/" << date->tm_mon + 1 << "/" << date->tm_year + 1900;
std::cout << " " << date->tm_hour << ":" << date->tm_min << std::endl;
// Wait for 1 minute (60 seconds)
sleep(60);
}
}
I have been looking around to get what I want but I couldn't find anything hence my question (hopefully not a duplicate!)
I am looking to get a microsecond resolution epoch time (to be converted to a Date string) of the clock perhaps using chrono.
Following is what works for me for seconds resolution:
auto secondsEpochTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << "Date string = " << ctime(&secondsEpochTime);
However when I change seconds to microseconds, ctime doesn't seem to reflect the correct date.
auto microSecondsEpochTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << "Date string = " << ctime(µSecondsEpochTime); // incorrect Date
Unfortunately std::chrono is not complete to provide a full answer to your question. You will have to use parts of the C library until C++23 at least otherwise you might end up with a race-prone implementation.
The idea is to get the timestamp and convert it to an integer as microseconds since epoch (1970-01-01).
Then use localtime_r to get the local time broken down in year/month/day/hour/minute/seconds and print it to string.
Finally append the milliseconds as an int padded to 3 digits and return the entire result as an std::string.
constexpr static int64_t ONEMICROSECOND = 1000000;
static std::string nowstr() {
auto now = std::chrono::system_clock::now();
auto onems = std::chrono::microseconds(1);
int64_t epochus = now.time_since_epoch()/onems;
time_t epoch = epochus/ONEMICROSECOND;
struct tm tms{};
localtime_r( &epoch, &tms );
char buf[128];
size_t nb = strftime( buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tms );
nb += ::sprintf( &buf[nb], ".%06d", int(epochus%ONEMICROSECOND) );
return std::string( buf, nb );
}
If you run this as-is it will likely return the timestamp in GMT. You will heave to set your timezone programatically if not set in the environment (as it happens with compiler explorer/Godbolt.
int main() {
setenv("TZ", "/usr/share/zoneinfo/America/New_York", 1);
std::cout << nowstr() << std::endl;
}
Results in
Program stdout
2022-10-01 22:51:03.988759
Compiler explorer link: https://godbolt.org/z/h88zhrr73
UPDATE: if you prefer to use boost::format (std::format is still incomplete on most compilers unfortunately) then you can do
static std::string nowstr() {
auto now = std::chrono::system_clock::now();
auto onems = std::chrono::microseconds(1);
int64_t epochus = now.time_since_epoch()/onems;
time_t epoch = epochus/ONEMICROSECOND;
struct tm tms{};
localtime_r( &epoch, &tms );
std::ostringstream ss;
ss << boost::format( "%04d-%02d-%02d %02d:%02d:%02d.%06d" )
% (tms.tm_year+1900) % (tms.tm_mon+1) % tms.tm_mday
% tms.tm_hour % tms.tm_min % tms.tm_sec
% (epochus%ONEMICROSECOND);
return ss.str();
}
You will have to use parts of the C library until C++23 at least
Umm... If your platform supports the full C++20 spec (at least with regards to format and chrono):
#include <chrono>
#include <format>
#include <iostream>
int
main()
{
auto tp = std::chrono::system_clock::now();
std::chrono::zoned_time zt{std::chrono::current_zone(),
std::chrono::time_point_cast<std::chrono::microseconds>(tp)};
std::cout << "Date string = " << std::format("{:%a %b %e %T %Y}", zt) << '\n';
}
Sample output:
Date string = Sat Oct 1 23:32:24.843844 2022
I am trying to format the time into hh::mm::ss then put it in a wide-string-stream. The code is as follows.
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::chrono::steady_clock::duration time_elapsed = end - start;
std::chrono::hh_mm_ss formatted {std::chrono::duration_cast<std::chrono::milliseconds> (time_elapsed)};
start is in the constructor of the class. using the << stream operators do not work and i do not see any way to convert this type to a string.
My question is how can i convert formatted to a string (c style, wstring, or normal string)?
The following works for me in MSVC.
As of 2021-08-12 I had to use the /std:c++latest switch with Visual Studio version 16.11.2 in order for this solution to work.
const auto start{ std::chrono::steady_clock::now( ) };
std::this_thread::sleep_for( std::chrono::milliseconds{ 1000 } );
const auto end{ std::chrono::steady_clock::now( ) };
const auto elapsed{ end - start };
std::chrono::hh_mm_ss formatted{
std::chrono::duration_cast<std::chrono::milliseconds>( elapsed ) };
std::cout << formatted << '\n';
// Or
std::stringstream ss{ };
ss << formatted;
std::cout << ss.str( ) << '\n';
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 looking for a way to save the time in a HH::MM::SS fashion in C++. I saw here that they are many solutions and after a little research I opted for time and localtime. However, it seems like the localtime function is a little tricky, since it says:
All calls to localtime and gmtime use the same static structure, so
each call overwrites the results of the previous call.
The problem that this causes is shown in the next snippet of code:
#include <ctime>
#include <iostream>
using namespace std;
int main() {
time_t t1 = time(0); // get time now
struct tm * now = localtime( & t1 );
std::cout << t1 << std::endl;
sleep(2);
time_t t2 = time(0); // get time now
struct tm * now2 = localtime( & t2 );
std::cout << t2 << std::endl;
cout << (now->tm_year + 1900) << '-'
<< (now->tm_mon + 1) << '-'
<< now->tm_mday << ", "
<< now->tm_hour << ":" << now->tm_min << ":" << now->tm_sec
<< endl;
cout << (now2->tm_year + 1900) << '-'
<< (now2->tm_mon + 1) << '-'
<< now2->tm_mday << ", "
<< now2->tm_hour << ":" << now2->tm_min << ":" << now2->tm_sec
<< endl;
}
A typical output for this is:
1320655946
1320655948
2011-11-7, 9:52:28
2011-11-7, 9:52:28
So as you can see, the time_t timestamps are correct, but the localtime messes everything up.
My question is: how do I convert a timestamp ot type time_t into a human-readable time?
If you are worried about reentrancy in localtime and gmtime, there is localtime_r and gmtime_r which can handle multiple calls.
When it comes to formatting the time to your liking, check the function strftime.
the localtime() call stores the results in an internal buffer.
Every time you call it you overwrite the buffer.
An alternative solution would be to make a copy of the buffer.
time_t t1 = time(0); // get time now
struct tm* now = localtime( & t1 ); // convert to local time
struct tm copy = *now; // make a local copy.
// ^^^ notice no star.
But note: The only time you should be converting to local time is when you display the value. At all other times you should just keep the time as UTC (for storage and manipulation). Since you are only converting the objects for display convert then print immediately and then things will not go wrong.
localtime has what is best considered a legacy interface. It can't be
used in multithreaded code, for example. In a multithreaded
environment, you can use localtime_r under Posix or localtime_s
under Windows. Otherwise, all you have to do is save the results:
tm then = *localtime( &t1 );
// ...
tm now = *localtime( &t2 );
It would probably be more idiomatic, however, to only call localtime
immediately before formatting the output, e.g.:
std::string
timestampToString( time_t timeAndDate )
{
char results[100];
if ( strftime( results, sizeof( results ), "%Y-%m-%d, %H:%M:%S",
localtime( &timeAndDate) ) == 0 ) {
assert( 0 );
}
return results;
}
and then writing:
std::cout << formatTime( t1 ) << std::endl;
(You could also create a more generic formatting function, which took
the format as an argument.)
You can run continuous clock using following code. It works nicely.
#include<iostream>
#include <Windows.h>
#include<ctime>
using namespace std;
void main() {
while(true) {
system("cls"); //to clear screen
time_t tim;
time(&tim);
cout << ctime(&tim);
Sleep(1);
}
}