I'm trying to convert a date string to a time_t, but mktime() is returning seemingly random dates:
string datetime = "2014-12-10 10:30";
struct tm tmInfo;
strptime(datetime.c_str(), "%Y-%m-%d %H:%M", &tmInfo);
tmInfo.tm_isdst = 0;
time_t eventTime = mktime(&tmInfo);
eventTime ranges wildly from the 1970s to the 2030s. The tmInfo struct holds the correct date, so the error must be happening in mktime(). Any ideas of what's going wrong?
You need to properly zero-initialize all of the other fields of the struct tm instance before calling strptime(), since it doesn't necessarily initialize every field. From the strptime() POSIX specification:
It is unspecified whether multiple calls to strptime() using the same tm structure will update the current contents of the structure or overwrite all contents of the structure. Conforming applications should make a single call to strptime() with a format and all data needed to completely specify the date and time being converted.
For example, this should suffice:
struct tm tmInfo = {0};
You have to initialize the struct to 0 beforehand or also input the seconds:
string datetime = "2014-12-10 10:30";
struct tm tmInfo = { 0 };
strptime(datetime.c_str(), "%Y-%m-%d %H:%M", &tmInfo);
or
string datetime = "2014-12-10 10:30:00";
struct tm tmInfo;
strptime(datetime.c_str(), "%Y-%m-%d %H:%M:%S", &tmInfo);
The below code would do the work, if you want current system time in an format
time_t current_time;
struct tm *loctime;
memset(buffer,0,strlen(buffer));
current_time = time(NULL);
loctime = localtime(¤t_time);
strftime(buffer,250,"--> %d/%m/%y %H:%M:%S",loctime);
Related
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;
}
A timestamp is an absolute value. It doesn't depend on timezones or DST. It represents the number of seconds since a fixed moment in the past. The value returned by time() is the same, no matter what the timezone of the server is.
Your code doesn't produce timestamps but dates formatted for human consumption.
I recommend you use timestamps internally and format them to dates readable by humans only in the UI. However, if you need to pass dates as strings between various components of your application, also put the timezone in them.
I would write your code like this (using only timestamps):
// The client side
time_t getTime()
{
return time(NULL);
}
// The server side
bool checkTimeStamp(time_t clientTime, double delay)
{
time_t now = time(NULL);
return difftime(now, clientTime) < delay;
}
Update
If you have to use strings to communicate between client and server then all you have to do is to update the format string used to format the timestamps as dates (on the client) and parse the dates back to timestamps (on the server), to include the timezone you used to format the date.
This means add %Z into the format everywhere in your code. Use "%d-%m-%Y %H:%M:%S %Z". Btw, the code you posted now reads "%d-%m-%Y %I:%M:%S" in the call to strptime() and that will bring you another problem in the afternoon.
Remark
I always use "%Y-%m-%d %H:%M:%S %Z" because it is unambiguous and locale-independent. 06-04-2016 can be interpreted as April 6 or June 4, depending of the native language of the reader.
I've got an 8601 format time string like so:
std::string strTime("1601-01-01T00:01:53.537Z");
I want to increment the hour and change its value to
"1601-01-01T01:01:53.537Z"
I think the steps are: convert string to a time object, increment the hour by 1, convert the object back to a string.
Of course, it would be helpful if all the normal time considerations and boundaries were taken into account (such as adding an hour to 11:30 pm will move to the next day, etc...). I've been looking at strftime, strptime, std::get_time and others but have not been able to work it out yet.
I'm using VS2012 on Windows. Thanks.
Some pseudo code to get you started.
char *AddHour(char *dest, size_t size, const char *timestamp) {
Initialize struct tm
Scan timestamp into tm
Check scanning success
Check year range validity
Bring into range acceptable by mktime()
Add hour
Call mktime()
Undo range adjustment made beforehand
Print tm to dest
return dest;
}
Even though mktime() uses local timezone, by keeping the tm_isdst == 0 we can use this for the Z timezone (UTC) for all practical purposes.
Simply scan the string into various parts. Add 1 hour and then reform the string
string --> struct tm tm;
// Add hour
if (++tm.tm_hour >= 24) {
tm.tm_hour = 0;
if (++tm.tm_mday > EOM(tm.tm_year, tm.tm_mon)) {
tm.tm_mday = 1;
if (++tm.tm_mon > 12) {
tm.tm_mon = 1;
tm.tm_year++;
}
}
}
struct tm tm --> string
I have written a C library that parses and formats a ISO 8601 calendar date with time and zone designator in extended format. It's available on Github, c-timestamp.
{
timestamp_t ts;
char *str = "1601-01-01T00:01:53.537Z";
timestamp_parse(str, strlen(str), &ts);
ts.sec += 1*60*60;
timestamp_format(str, strlen(str), &ts);
puts(str);
}
the member tm_mon, in struct tm is stored as an integer. I'm looking for another time stuct that stores the actual name of the month. I can get the user-friendly format with
ctime();
but how can I selectively output just the month?
Have an array like,
string Months[] = {"January", "February", ... };
Then when you want to print use,
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
cout << Months[now-> tm_mon];
I appended date to the mongodb like this
bson_append_date(b,"uploadDate",(bson_date_t)1000*time(NULL));
Do remember that this will append "milliseconds since epoch UTC" and saved as 2014-06-27 06:11:56
Now i am reading it out and it is giving milliseconds (1403852029) which is exactly right. Now i want to convert it into local time. I tried to use the localtime function of C++ but did get success as the time returned by mongodb is in int64_t.
if(bson_iterator_type(&it)==BSON_DATE)
bson_date_t date_it = bson_iterator_date( &it );
where bson_date_t is typedef int64_t bson_date_t;. Can anyone tell me how i can get the local time from the milliseconds.
Getting a valid time_t that would work with localtime should be exactly the opposite of what you are doing in the forward conversion:
bson_append_date(b,"uploadDate",(bson_date_t)1000*time(NULL));
To have a workable time_t, you should do following:
time_t rawTime = (time_t)(bson_iterator_date( &it ) / 1000);
struct tm * timeinfo = localtime (&rawTime);
One more method.
bson_date_t date_it = bson_iterator_date( &it );
struct tm* ts;
time_t epoch_time_as_time_t= date_it/1000;
ts=localtime(&epoch_time_as_time_t);
strftime(upload_Date,sizeof(upload_date),"%a %Y-%m-%d %H:%M:%S %Z",ts);
My question is pretty much in the title. I have a function call with a parameter of type time_t, and I need to initialize a variable to today's date, month, and year, and send it via the argument. For example,
void WebCall(time_t TodaysDate)
Where TodaysDate is the populated variable with the format DD/MM/YYYY with the slashes included. Is this possible? I can't change the data type from time_t to SYSTEMTIME or anything else. This is coded in C++. Any Ideas?
If you mean time_t, you can format it using gmtime and strftime:
time_t TodaysDate= ...;
struct tm * ptm= gmtime(&time);
char buffer[80];
strftime(buffer, 80, "%d/%m/%Y", ptm);
time_t is "unix time" and is the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. As MSN answered you can convert that to a date using gmtime, for most common purposes, UTC is synonymous with GMT. You didn't specify in the question but if you need the local date use localtime instead of gmtime. Here's a function that'll do that for you and return a std::string:
#include <time.h>
#include <string>
std::string time_to_local_date( time_t utc )
{
struct tm *now = localtime(&utc);
char buffer[80];
strftime(buffer, 80, "%d/%m/%Y", now);
return std::string(buffer);
}