C++: Converting date-time between timezones keeping precision - c++

Consider the input: 2014-04-14T16:28:07.023 (no time-zone, milliseconds precision)
I parsed it and I have the parts as numbers.
The input is always considered to be in UTC
I want to display it as local time
I want to keep the milliseconds precision when displaying
I have C++98 and boost 1.51.
I inspected high_resolution_clock and system_clock, but was unable to produce the final plot for the problem yet.

As requested in the comments to post as an answer, here is how it can be done without Boost:
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main() {
int year, month, day, hour, minute, second, millisecond;
if (std::cin >> year >> month >> day >> hour >> minute >> second >> millisecond) {
struct tm utc;
utc.tm_year = year;
utc.tm_mon = month;
utc.tm_mday = day;
utc.tm_hour = hour;
utc.tm_min = minute;
utc.tm_sec = second;
utc.tm_isdst = 0;
time_t time = timegm(&utc);
if (time == (time_t) -1)
abort();
struct tm *local = localtime(&time);
if (localtime == NULL)
abort();
year = local->tm_year;
month = local->tm_mon;
day = local->tm_mday;
hour = local->tm_hour;
minute = local->tm_min;
second = local->tm_sec;
std::cout << year << ' ' << month << ' ' << day << ' ' << hour << ' ' << minute << ' ' << second << ' ' << millisecond << std::endl;
}
}
Note that the millisecond variable is read from input, and written to output, without any modification.
This uses the non-standard timegm function, but the documentation for that function contains a more portable implementation that you could include, if you want.

I have a solution which will be sufficient for me, but I don't know if it is the best approach in general or not. I'm about to use boost::posix_time::ptime and boost::date_time's c_local_adjustor:
#include <iostream>
#include <boost/date_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>
int main()
{
typedef boost::posix_time::ptime TP;
typedef boost::date_time::c_local_adjustor<TP> local_adj;
TP tUTC(boost::gregorian::date(2014,4,13),boost::posix_time::millisec(23));
TP tLocal(local_adj::utc_to_local(tUTC));
std::cout << boost::posix_time::to_simple_string(tUTC) << std::endl;
std::cout << boost::posix_time::to_simple_string(tLocal) << std::endl;
return 0;
}
Will print:
2014-Apr-13 00:00:00.023000
2014-Apr-13 02:00:00.023000
I did'nt use using namespace to show where is what. The ptime class has accessors to every detail I need. The c_local_adjustor does not have local_to_utc method, but it can be worked around.
(I got nowhere with chrono, I was able to do only circles in the documentation.)

Related

Getting Current Date inside a C++ process running 24*7

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(&currentTime);
// 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(&currentTime);
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);
}
}

How to correctly read and increment dates in c++ using localtime and mktime?

I am struggling to execute a simple task. I want to take a date parameter from the command line argument and increment it several times by 1 day. The basic program should:
read the command line argument as the starting date, and
loop several times, incrementing that date by 1 day every time.
I convert the char* command line argument to a struct tm, then convert the struct tm to a time_t and add 60 * 60 * 24 = 1 day to it. I convert it back to struct tm to print it.
Here is the code:
#include <iostream>
#include <cstdlib>
#include <string>
#include "time.h"
int main(int argc, char *argv[])
{
char* start_date;
tm tm_start_date = {}; // solution: needs initialization
start_date = argv[1];
strptime(start_date, "%Y-%m-%d", &tm_start_date); // YYYY-MM-DD
char ch_stmt_date[11] = "";
time_t t_stmt_date = 0;
tm tm_stmt_date = {}; // solution: needs initialization;
tm_stmt_date = tm_start_date;
// time_t -> tm localtime_r(time_t, tm)
// tm -> time_t mktime(tm) returns time_t
std::cout << "start_date: " << start_date << " / tm_start_date: " << std::to_string(1900 + tm_start_date.tm_year) + std::to_string(tm_start_date.tm_mon + 1) +
std::to_string(tm_start_date.tm_mday) << std::endl;
// increment by 1 day per iteration
for (int i=0; i<5; i++)
{
// tm -> t_time
t_stmt_date = mktime(&tm_stmt_date);
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// + 1 day
t_stmt_date += 60*60*24;
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// time_t -> tm
localtime_r(&t_stmt_date, &tm_stmt_date);
strftime (ch_stmt_date, 11, "%Y-%m-%d", &tm_stmt_date);
std::cout << "ch_stmt_date: " << ch_stmt_date << std::endl;
}
return EXIT_SUCCESS;
}
The start date is correctly read and parsed into the struct tm.
However, subsequently I get one of two behaviors of the program:
Either I get a -1 on the first call of t_stmt_date = mktime(&tm_stmt_date); and a value of t_stmt_date: 86399 (1970-01-02) in the output. The rest of the loop then works correctly and iterates 5 times, incrementing 1970-01-02 by 1 day.
Or, the same code using the same command line parameter parses a nonsensical value on the first call of t_stmt_date = mktime(&tm_stmt_date); in the loop which is not a valid date, which, however is also correctly incremented by 60*60*24 on each of the 5 loops.
At this point I am desperate to understand the issue. I am working on Ubuntu 20.04 using gcc.
Thanks for your help.
Edit: Initializing the struct tm did the trick!
[NOTE]
You explicitly mention "using localtime and mktime" in the question's title, but I wasn't sure though after reading the rest of the text if that was mandatory, or you just needed to get a task done.
If you cannot use other libraries, just let me know and I'll remove this answer.
You could use std::chrono and Howard Hinnant's date library (C++11 onwards, header-only).
Or, should you be able to use a C++20 compiler, you would only need std::chrono.
[Demo]
#include <chrono>
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
#include "date/date.h"
int main()
{
namespace ch = std::chrono;
namespace dt = date;
const std::string start_date{"2022-01-31"}; // date
std::istringstream iss{ start_date }; // to string stream
dt::sys_days start_day{}; // to a time point with a day duration
dt::from_stream(iss, "%Y-%m-%d", start_day);
for (auto day{start_day}, end_day{start_day + dt::days{3}};
day < end_day;
day += dt::days{1}) // with which we can do date arithmetic
{
std::cout << dt::format("%Y-%m-%d\n", day);
}
}
// Outputs:
//
// 2022-01-31
// 2022-02-01
// 2022-02-02

From xs:dateTime to std::chrono::timepoint [duplicate]

Consider a historic date string of format:
Thu Jan 9 12:35:34 2014
I want to parse such a string into some kind of C++ date representation, then calculate the amount of time that has passed since then.
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
Can this be done with the new C++11 std::chrono namespace? If not, how should I go about this today?
I'm using g++-4.8.1 though presumably an answer should just target the C++11 spec.
std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
GCC prior to version 5 doesn't implement std::get_time. You should also be able to write:
std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
New answer for old question. Rationale for the new answer: The question was edited from its original form because tools at the time would not handle exactly what was being asked. And the resulting accepted answer gives a subtly different behavior than what the original question asked for.
I'm not trying to put down the accepted answer. It's a good answer. It's just that the C API is so confusing that it is inevitable that mistakes like this will happen.
The original question was to parse "Thu, 9 Jan 2014 12:35:34 +0000". So clearly the intent was to parse a timestamp representing a UTC time. But strptime (which isn't standard C or C++, but is POSIX) does not parse the trailing UTC offset indicating this is a UTC timestamp (it will format it with %z, but not parse it).
The question was then edited to ask about "Thu Jan 9 12:35:34 2014". But the question was not edited to clarify if this was a UTC timestamp, or a timestamp in the computer's current local timezone. The accepted answer implicitly assumes the timestamp represents the computer's current local timezone because of the use of std::mktime.
std::mktime not only transforms the field type tm to the serial type time_t, it also performs an offset adjustment from the computer's local time zone to UTC.
But what if we want to parse a UTC timestamp as the original (unedited) question asked?
That can be done today using this newer, free open-source library.
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
}
This library can parse %z. And date::sys_seconds is just a typedef for:
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
The question also asks:
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
That part has remained unanswered. Here's how you do it with this library.
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
auto hms = hh_mm_ss<seconds>{tp - tp_days};
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
}
floor<days> truncates the seconds-precision time_point to a days-precision time_point. If you subtract the days-precision time_point from tp, you're left with a duration that represents the time since midnight (UTC).
The type hh_mm_ss<seconds> takes any duration convertible to seconds (in this case time since midnight) and creates a {hours, minutes, seconds} field type with getters for each field. If the duration has precision finer than seconds this field type will also have a getter for the subseconds. Prior to C++17, one has to specify that finer duration as the template parameter. In C++17 and later it can be deduced:
auto hms = hh_mm_ss{tp - tp_days};
Finally, one can just print out all of these durations. This example outputs:
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
So 2014-01-09 is 16079 days after 1970-01-01.
Here is the full example but at milliseconds precision:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34.123 +0000"};
sys_time<milliseconds> tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
hh_mm_ss hms{tp - tp_days};
std::cout << tp << '\n';
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
std::cout << "Number of milliseconds = " << hms.subseconds() << '\n';
}
Output:
2014-01-09 12:35:34.123
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
Number of milliseconds = 123ms
This library is now part of C++20, but is in namespace std::chrono and found in the header <chrono>.
This is rather C-ish and not as elegant of a solution as Simple's answer, but I think it might work. This answer is probably wrong but I'll leave it up so someone can post corrections.
#include <iostream>
#include <ctime>
int main ()
{
struct tm timeinfo;
std::string buffer = "Thu, 9 Jan 2014 12:35:00";
if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
std::cout << "Error.";
time_t now;
struct tm timeinfo2;
time(&now);
timeinfo2 = *gmtime(&now);
time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
time(&seconds);
struct tm result;
result = *gmtime ( &seconds );
std::cout << result.tm_sec << " " << result.tm_min << " "
<< result.tm_hour << " " << result.tm_mday;
return 0;
}
Cases covered (code is below):
since a give date until now
long int min0 = getMinutesSince( "2005-02-19 12:35:00" );
since the epoch until now
long int min1 = getMinutesSince1970( );
between two date+hours (since the epoch until a given date)
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
cout << min1 - min0 << endl;
Complete code:
#include <iostream>
#include <chrono>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970Until( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(mktime(&tm));
return
chrono::duration_cast<chrono::minutes>(
tp.time_since_epoch()).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970() {
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>( now.time_since_epoch() ).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point then =
chrono::system_clock::from_time_t(mktime(&tm));
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>(
now.time_since_epoch()-
then.time_since_epoch()
).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
int main () {
long int min = getMinutesSince1970Until( "1970-01-01 01:01:00" );
cout << min << endl;
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
if ( (min1 - min0) != 4 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
min0 = getMinutesSince( "1970-01-01 01:00:00" );
min1 = getMinutesSince1970( );
if ( (min1 - min0) != 0 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
} // ()

Convert Date-Time to Milliseconds - C++ - cross platform

I want to convert a string in the format of "20160907-05:00:54.123" into milliseconds.
I know that strptime is not available in Windows and I want to run my program in both windows and linux. I can't use third party libraries as well.
I can tokenize the string and convert it. But is there a more elegant way like using the strptime to do so?
What about std::sscanf?
#include <iostream>
#include <cstring>
int main() {
const char *str_time = "20160907-05:00:54.123";
unsigned int year, month, day, hour, minute, second, miliseconds;
if (std::sscanf(str_time, "%4u%2u%2u-%2u:%2u:%2u.%3u", &year, &month,
&day, &hour, &minute, &second,&miliseconds) != 7)
{
std::cout << "Parse failed" << std::endl;
}
else
{
std::cout << year << month << day << "-" << hour << ":"
<< minute << ":" << second << "." << miliseconds
<< std::endl;
}
}
Output (ideone):
201697-5:0:54.123.
However, you should make sure the input is valid (for example, day can be in the range of [0,99]).
Too bad about no 3rd party libraries, because here is one (MIT license) that is just a single header, runs on linux and Windows, and handles the milliseconds seamlessly:
#include "date.h"
#include <iostream>
#include <sstream>
int
main()
{
date::sys_time<std::chrono::milliseconds> tp;
std::istringstream in{"20160907-05:00:54.123"};
date::parse(in, "%Y%m%d-%T", tp);
std::cout << tp.time_since_epoch().count() << '\n';
}
This outputs:
1473224454123
Error checking is done for you. The stream will fail() if the date is invalid.
date::sys_time<std::chrono::milliseconds> is a type alias for std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>. I.e. it is from the family of system_clock::time_point, just milliseconds precision.
Fully documented:
https://howardhinnant.github.io/date/date.html
Doesn't get much more elegant than this.
Given the format of your string, it is fairly easy to parse it as follows (although a regex or get_time might be more elegant):
tm t;
t.tm_year = stoi(s.substr(0, 4));
t.tm_mon = stoi(s.substr(4, 2));
t.tm_mday = stoi(s.substr(6, 2));
t.tm_hour = stoi(s.substr(9, 2));
t.tm_min = stoi(s.substr(12, 2));
t.tm_sec = 0;
double sec = stod(s.substr(15));
Finding the time since the epoch can be done with mktime:
mktime(&t) + sec * 1000
Note that the fractional seconds need to be handled differently - unfortunately, tm has only integer seconds.
(See the full code here.)
Edit
As Mine and Panagiotis Kanavos correctly note in the comments, Visual C++ apparently supports get_time for quite a while, and it's much shorter with it (note that the fractional seconds need to be handled the same way, though).

How to append system time to a string variable

#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int main()
{
string NowTime;
time_t now;
struct tm nowLocal;
now=time(NULL); // get the time from the OS
nowLocal=*localtime(&now);
NowTime = nowLocal.tm_hour + ':' + nowLocal.tm_min + ':' + nowLocal.tm_sec;
cout<< NowTime;
}
When I run the program, it display nothing, can someone help me? I am totally new in programming.
If you try
cout << nowLocal.tm_hour + ':' + nowLocal.tm_min + ':' + nowLocal.tm_sec;
you'll see an integer, not anything resembling a time.
This is because it's the sum of five integers - the characters are promoted to integers, and then it's all added up.
The simplest fix is to not build a string at all but to output the parts individually:
cout << nowLocal.tm_hour << ':' << nowLocal.tm_min << ':' << nowLocal.tm_sec;
Otherwise, you need to convert those numbers to strings:
NowTime = std::to_string(nowLocal.tm_hour) + ':' + std::to_string(nowLocal.tm_min) + ':' + std::to_string(nowLocal.tm_sec);
or, you can use a std::ostringstream, which works just like std::cout and other streams, but writes to a std::string:
std::ostringstream ss;
ss << nowLocal.tm_hour << ':' << nowLocal.tm_min << ':' << nowLocal.tm_sec;
NowTime = ss.str();
The line:
NowTime = nowLocal.tm_hour + ':' + nowLocal.tm_min + ':' + nowLocal.tm_sec;
is adding the hour, minute, and second to the numeric value of the colon symbol, since char is implicitly coerced to an int. That value is then being interpreted as a char in the string assignment operator.
Instead, you can simply output the values directly to cout. They will be formatted appropriately by cout's stream insertion operator <<.
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int main()
{
string NowTime;
time_t now;
tm nowLocal;
now=time(NULL); // get the time from the OS
nowLocal=*localtime(&now);
cout << nowLocal.tm_hour << ':' << nowLocal.tm_min << ':' << nowLocal.tm_sec;
return 0;
}
If you would instead want to store them in a string, read up about stringstreams. They have a similar syntax to cout and can make formatting strings much easier.
Instead of having to put the result in a variable, you could output it like this:
cout << nowLocal.tm_hour << ':' << nowLocal.tm_min << ':' << nowLocal.tm_sec;
Live Example
Also, if you want to keep the variable, do this:
NowTime = std::to_string(nowLocal.tm_hour) + ':' + std::to_string(nowLocal.tm_min) + ':' + std::to_string(nowLocal.tm_sec);
cout << NowTime;
Try this:
#include<iostream>
#include<ctime>
#include<string>
#include <sstream>
using namespace std;
int main()
{
string NowTime;
time_t now;
struct tm nowLocal;
now=time(NULL); // get the time from the OS
nowLocal=*localtime(&now);
stringstream s;
s<<nowLocal.tm_hour;
s<<":";
s<<nowLocal.tm_min;
s<<":";
s<<nowLocal.tm_sec;
NowTime = s.str();
cout<< NowTime;
}
You cannot cas directly from int to string and you need put values into stream and then to string.
What about using iostringstream to build the string you want?
#include<iostream>
#include<ctime>
#include<string>
#include <sstream>
using namespace std;
int main()
{
ostringstream NowTime;
time_t now;
struct tm nowLocal;
now=time(NULL); // get the time from the OS
nowLocal=*localtime(&now);
NowTime << nowLocal.tm_hour << ":" << nowLocal.tm_min << ":" << nowLocal.tm_sec;
cout<< NowTime.str() << endl;
}
Or for the purposes of your program you could simple use std::cout which also happens to be an output stream.
cout << nowLocal.tm_hour << ":" << nowLocal.tm_min << ":" << nowLocal.tm_sec << endl;
Since it looks like you're pre-c++11 and can't use std::to_string. Here's a C-like way of doing it, sticking to the includes you're currently using.
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
#define STR_LEN 128
int main()
{
string nowTime;
time_t now;
struct tm nowLocal;
now = time( NULL ); // get the time from the OS
nowLocal = *localtime( &now );
char hour[ STR_LEN ], min[ STR_LEN ], sec[ STR_LEN ];
sprintf( hour, "%d", nowLocal.tm_hour );
sprintf( min, "%d", nowLocal.tm_min );
sprintf( sec, "%d", nowLocal.tm_sec );
nowTime = string( hour ) + ':' + string( min ) + ':' + string( sec );
cout << nowTime << endl;
}
How append system time to a string?
My answer is to build a convenience function.
If you really only need hour, minute, second, then you need not use the relatively slow localtime(). (on the other hand, if you do need more, I think you should prefer localtime_r() for the conversion).
For an embedded system several contracts back, I found this conversion to be a relatively slow function and chose to avoid it. The algorithms to handle leap days, centuries, etc. appear simple enough. I suspect I considered it slow simply because it calculates more than I needed in that application that was trying to do the conversion many times per second.
There exists a simpler (and probably still faster) approach involving modular arithmetic. It starts the same - with a time(0) (and thus I suspect what I am doing here is 'hidden' in the localtime_r() function). Side note 1 - on my older Dell running Ubuntu 15.10, time(0) is simply the fastest access to the wall clock, measuring about 6 or 7 ns 'typical' duration. Side note 2 - time_t may change someday. "The time_t Wikipedia article article sheds some light on this. The bottom line is that the type of time_t is not guaranteed in the C specification."
The code I currently use to conveniently generate a time stamp string:
std::string hhCmmCssGet(time_t tt = 0) // tt has default value
{
time_t now = ( tt ? tt : time(0) );
static time_t prev = 0;
static char hhmmss[] = "hh:mm:ss";
if (prev != now)
{
prev = now;
const int32_t CST = -6;
int64_t hr = ((now / 3600) % 24) + CST; // hr of day, CST offset
if (hr < 0) hr += 24;
uint64_t min = ((now / 60) % 60); // min of day
uint64_t sec = (now % 60); // sec of day
std::stringstream ss;
ss << std::dec
<< std::setfill('0') << std::setw(2) << hr << ":"
<< std::setfill('0') << std::setw(2) << min << ":"
<< std::setfill('0') << std::setw(2) << sec;
for (size_t i=0; i<8; i++) // transfer new value
hhmmss[i] = ss.str()[i]; // into static hhmmss
}
std::string retVal(hhmmss);
return(retVal);
}
The static items and "if (prev != now)" clause, allow this function to be invoked thousands of times per second ... with much reduced effort. The second, after all, only updates 1ce per second. And note that the std::stringstream stuff and modular arithmetic operations only run 1ce per second.