I'm working on a client-server custom application (to be run on linux), and one of the frames I send include a timestamp (ie the time at which the frame is send).
In order to make my application reliable, I used gmtime
to produce the time on the client. I'm in Belgium, so right now the hour of the client VM is 2 hours later than the UTC time (because of the summer hour).
In the server side, I first convert the recieved string to a time_t
type. I do this to use the difftime
function to see if the timestamp is not too old.
Then, I generate a timestamp (in UTC time) again with gmtime
, and I convert it to a time_t
.
I compare then the two time_t
to see the time difference.
I have got a problem with the conversion of the time at the server side. I use the same code as in the client, but the outputted gmtime
is different...
Client Side : function to generate the timestamp, and export it to a string (time_str
):
std::string getTime()
{
time_t rawtime;
struct tm * timeinfo;
char buffer[80];
time (&rawtime); // Get time of the system
timeinfo = gmtime(&rawtime); // Convert it to UTC time
strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo);
std::string time_str(buffer); // Cast it into a string
cout<<"Time Stamp now (client) : "<<time_str<<endl;
return time_str;
}
And it produices this (at 9h33 local time) :
Time Stamp now : 06-04-2016 07:33:30
Server Side : fucntion to retrieve the timestamp, generate the newx time stamp, and compare them :
bool checkTimeStamp(std::string TimsStamp_str, double delay)
{
cout<<"TimeStamp recieved: "<<TimsStamp_str<<endl;
/* Construct tm from string */
struct tm TimeStampRecu;
strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);
time_t t_old = mktime(&TimeStampRecu);
/* Generate New TimeStamp */
time_t rawtime;
struct tm * timeinfo;
time (&rawtime); // Get time of the system
timeinfo = gmtime(&rawtime); // convert it to UTC time_t
time_t t2 = mktime(timeinfo); // Re-Cast it to timt_t struct
/* Convert it into string (for output) */
char buffer[80];
strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo);
std::string time_str(buffer); // Cast it into a string
cout<<"Time Stamp now (server) : "<<time_str<<endl;
/* Comparison */
double diffSecs = difftime(t2, t_old);
cout<<diffSecs<<endl;
bool isTimeStampOK;
if (diffSecs < delay)
isTimeStampOK = true;
else
isTimeStampOK = false;
return isTimeStampOK;
}
And it produces this (at 9h33 in Belgium) :
TimeStamp recieved : 06-04-2016 07:33:30
Time Stamp now (server) : 06-04-2016 08:33:31
Why is the Server Time (8h33) neither in localtime (9h33), neither in UTC time (7h33) ?
Have I made a mistake in its generation ? I don't understand where, because these are the exact same code as in the client side...
There's a couple of errors in your code, some your fault, some not. The biggest problem here is that the C <time.h>
API is so poor, confusing, incomplete and error prone that errors like this are very nearly mandatory. More on that later.
The first problem is this line:
struct tm TimeStampRecu;
It creates an uninitialized tm
and then passes that into strptime
. strptime
may not fill in all the fields of TimeStampRecu
. You should zero-initialize TimeStampRecu
like this:
struct tm TimeStampRecu{};
Next problem:
strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);
The 12-hour time denoted by %I
is ambiguous without an AM/PM specifier. I suspect this is just a type-o as it is the only place you use it.
Next problem:
gmtime time_t -> tm UTC to UTC
mktime tm -> time_t local to UTC
That is, mtkime
interprets the input tm
according to the local time of the computer it is running on. What you need instead is:
timegm tm -> time_t UTC to UTC
Unfortunately timegm
isn't standard C (or C++). Fortunately it probably exists anyway on your system.
With these changes, I think your code will run as expected.
If you are using C++11, there is a safer date/time library to do this here (free/open-source):
https://github.com/HowardHinnant/date
Here is your code translated to use this higher-level library:
std::string getTime()
{
using namespace std::chrono;
auto rawtime = time_point_cast<seconds>(system_clock::now());
auto time_str = date::format("%d-%m-%Y %H:%M:%S", rawTime);
std::cout<<"Time Stamp now (client) : "<<time_str<< '\n';
return time_str;
}
bool checkTimeStamp(std::string TimsStamp_str, std::chrono::seconds delay)
{
using namespace std::chrono;
std::cout<<"TimeStamp recieved: "<<TimsStamp_str<< '\n';
/* Construct tm from string */
std::istringstream in{TimsStamp_str};
time_point<system_clock, seconds> t_old;
date::parse(in, "%d-%m-%Y %H:%M:%S", t_old);
/* Generate New TimeStamp */
auto rawtime = time_point_cast<seconds>(system_clock::now());
auto time_str = date::format("%d-%m-%Y %H:%M:%S", rawTime);
in.str(time_str);
time_point<system_clock, seconds> t2;
date::parse(in, "%d-%m-%Y %H:%M:%S", t2);
cout<<"Time Stamp now (server) : "<<time_str<<endl;
/* Comparison */
auto diffSecs = t2 - t_old;
cout<<diffSecs.count()<<endl;
bool isTimeStampOK;
if (diffSecs < delay)
isTimeStampOK = true;
else
isTimeStampOK = false;
return isTimeStampOK;
}