Convert a time (UTC ) given as a string to local time - c++

I have a time string like this "132233" (Time only no date) and i want to convert it into local time.
So, in order to use the function localtime(), I first converted my string into time_t using mktime() (thanks to How to convert a string variable containing time to time_t type in c++? )and then printed the time after conversion using strftime as shown in (http://www.cplusplus.com/reference/ctime/strftime/)
I am getting a serious run time error. Can any one please tell me whats wrong. Thanks in advance
int main()
{
string time_sample="132233";
std::string s_hrs (time_sample.begin(), time_sample.begin()+2);
std::string s_mins (time_sample.begin()+2,time_sample.begin()+4);
std::string s_secs (time_sample.begin()+4,time_sample.begin()+6);
int hrs = atoi(s_hrs.c_str());
int mins = atoi(s_mins.c_str());
int secs = atoi(s_secs.c_str());
struct tm time_sample_struct = {0};
time_sample_struct.tm_hour = hrs;
time_sample_struct.tm_min = mins;
time_sample_struct.tm_sec = secs;
time_t converted_time;
converted_time = mktime(&time_sample_struct);
struct tm * timeinfo;
char buffer[80];
timeinfo = localtime(&converted_time);
strftime(buffer,80,"%I:%M:%S",timeinfo);
puts(buffer);
cout<<endl;
getch();
return 0;
}

Your problem is that if time_t is a 32 bit value, the earliest possible date it's capable of encoding (given a 1970-1-1 epoch) is 1901-12-13.
However you're not setting the date fields of your tm struct, which means it is defaulting to 0-0-0 which represents 1900-1-0 (since tm_day is 1-based, you actually end up with an invalid day-of-month).
Since this isn't representable by a 32-bit time_t the mktime function is failing and returning -1, a situation you're not checking for.
Simplest fix is to initialise the date fields of the tm struct to something a time_t can represent:
time_sample_struct.tm_year = 114;
time_sample_struct.tm_mday = 1;

Related

Parsing date and time string into a number to compare C++

My application receives a date and time string. I need to be able to parse this string and compare it to the current time in seconds.
I am parsing this as below into a struct tm t to get the year, month, day, hour, minute, and second separately.
std::string timestr = "2020-12-18T16:40:07";
struct tm t = {0};
sscanf(timestr.c_str(), "%04d-%02d-%02dT%02d:%02d:%02d",
&t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_sec);
I'm not sure if I need to convert this to epoch time, but when I do , I get -1. I'm not sure why.
time_t t_of_day;
t_of_day = mktime(&t);
Do I actually need to convert this to epoch first?
What is the best way for me to get the current time in seconds and then compare it to the time information I get in t? Thanks.
You want C++ parsing:
https://en.cppreference.com/w/cpp/io/manip/get_time
std::stringstream timestr = "2020-12-18T16:40:07";
struct tm t = {0};
timestr >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S");
I should note there is a bug in your code as: tm_year is not the same as year as we know it. This is the number of years since 1900!
https://www.cplusplus.com/reference/ctime/tm/
So your code needs another line:
t.tm_year -= 1900;
Note: std::get_time() already does that compensation.
This is probably why mktime() is returning -1 as the year 3920 is out of range.
Just use the features of chrono library:
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
auto epoch = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
but you don't need to convert it to epoch. Use std::chrono::time_point comparison like:
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
auto now = std::chrono::system_clock::now();
std::cout << (tp == now) << std::endl;

how to convert struct tm to time_t in c++

the given function is a part of a class which is used to handle date and time.the file i parse needs to convert the given string data to time_t yet mktime does not work. why?
struct tm DateTimeUtils::makeTime(string arrTime)//accepts in format"2315"means 11.15 pm
{
struct tm neww;
string hour = arrTime.substr(0,2);
int hour_int = stoi(hour);
neww.tm_hour=hour_int;//when this is directly printed generates correct value
string minute = arrTime.substr(2,2);
int minute_int = stoi(minute);
neww.tm_min=(minute_int);//when this is directly printed generates correct value
time_t t1 = mktime(&neww);//only returns -1
cout<<t1;
return neww;
}
From the mktime(3) man page:
time_t ... represents the number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
Then you have the fields of struct tm and particularly this one:
tm_year
The number of years since 1900.
So basicaly if the tm_year is set to 0 and we do the math correctly, we get a 70 year difference that needs to be expressed in seconds, and that's probably too big.
You can solve this by initialising your struct tm value to the Epoch and use that as a base reference:
struct tm DateTimeUtils::makeTime(string arrTime)//accepts in format"2315"means 11.15 pm
{
time_t tmp = { 0 };
struct tm neww = *localtime(&tmp);
string hour = arrTime.substr(0,2);
int hour_int = stoi(hour);
neww.tm_hour=hour_int;//when this is directly printed generates correct value
string minute = arrTime.substr(2,2);
int minute_int = stoi(minute);
neww.tm_min=(minute_int);//when this is directly printed generates correct value
time_t t1 = mktime(&neww);//only returns -1
cout<<t1;
return neww;
}
Clearing the struct before usage usually helps in this case:
struct tm neww;
memset((void *)&neww, 0, sizeof(tm));
Usually time_t is defined as 64 bit integer which resolves in a range of
-2^63 to +2^63-1 (-9223372036854775808 to +9223372036854775807)
which is roughly from -292 bilion years to +292 from the epoch.
However. If, fpor some reason, on your system time_t is just defined as 32 bit integer (16 bit embedded system or weird architecture or header files) we get a range from
2^31 to 2^31-1 (-2147483648 to +2147483647)
being roughly from -68 years to +68 years.
You could solve this problem by redefining time_t before calling mktime().
#define time_t long int
or if really using an 16 bit system
#define time_t long long int

Getting time difference using a time_t converted from a string

I am trying to get the diff between two dates.
One date being right now and the other is a date converted to time_t from a string representation of a date.
My code is as follows
const char *time_details = "12/03/2014";
struct tm tm;
strptime(time_details, "%m/%d/%Y", &tm);
time_t mytime = mktime(&tm);
time_t now;
time(&now);
double seconds = difftime(now, mytime);
LOGG("now = %d", now);
LOGG("mytime = %d", mytime);
LOGG("unsigned int mytime = %d", (int)mytime);
My output looks like so:
now = 1417830679
mytime = -1
seconds = 1610001720
mytime always comes out to -1
And, the value for seconds is not correct either.
Add before use (and you might want to pick a different name for the variable)
memset(&tm, 0, sizeof(struct tm));
See Notes section in strptime(3)

Converting localtime to time_t (C++)

I creating date() function on C++ http://aliarth.lt/date.cpp and I got one problem with localtome_to_time() conversion. Does anyone know how that local_time variable:
int time_integer = 12345;
time_t time = (time_t)time_integer;
tm *local_time = localtime(&time);
local_time->tm_year = 100;
local_time->tm_mon = 10;
local_time->tm_mday = 1;
Convert to time_t?
Try mktime, here is its signature:
time_t mktime (struct tm * timeptr);
Returns the value of type time_t that represents the local time described by the tm structure pointed by timeptr (which may be modified).

difference seen in difftime and strftime values

I'm seeing a difference in time functions and was wondering what was the reason.
currently, I'm using localtime, mktime, strftime and difftime:
time_t ltime;
ltime = time(NULL);
StartTM = localtime(&ltime);
time_t time1 = mktime(StartTM );
char startbuffer [128];
strftime( start_buffer, 128, "%H:%M:%S", StartTM );
<<Do some stuff, take some time >>>
time_t ttime;
ttime = time(NULL);
StopTM = localtime(&ttime);
time_t time2 = mktime(StopTM );
char stop_buffer [128];
strftime( stop_buffer, 128, "%H:%M:%S:", StopTM );
double wtinsec = difftime(time2, time1);
Executed, the output looks like this:
Stop buffer=08:46:18
Start buffer=08:44:11
wtinsec=129
Subtracting start from stop by hand, the length of time is 2:07, however the total number of seconds (difftime) says 2:09. As both times are using the same raw data (time1, time2) for both calculations, my initial thoughts was combination of lack of precision in the strftime conversion and difftime is the cause of this.
But the difference is not constant. If the time between the 2 local calls is small (like 10 seconds) there is no difference. However, as the time between the 2 time calls gets longer, the difference in time totals becomes larger. At 2 mins, its 2 seconds at 5 mins its 4 seconds and so on...
Any reason why this is happening and is there anything more accurate (in C++) preferably in micro/milliseconds that can track time of day and subtract one from another?
Thanks.
The values in ltime and time1 should be identical; the round trip through localtime() and mktime() should give you the answer you started with. Similarly, of course, for ttime and time2.
This C code demonstrates the expected behaviour. You need to look hard at your code to find out what is going wrong.
#include <stdio.h>
#include <time.h>
#include <unistd.h>
int main(void)
{
time_t ltime = time(NULL);
struct tm *start = localtime(&ltime);
time_t time1 = mktime(start);
char startbuffer[128];
strftime(startbuffer, sizeof(startbuffer), "%H:%M:%S", start);
printf("lt = %10lu, t1 = %10lu, time = %s\n",
(unsigned long)ltime, (unsigned long)time1, startbuffer);
sleep(10);
time_t ttime = time(NULL);
struct tm *finis = localtime(&ttime);
time_t time2 = mktime(finis);
strftime(startbuffer, sizeof(startbuffer), "%H:%M:%S", finis);
printf("lt = %10lu, t1 = %10lu, time = %s\n",
(unsigned long)ttime, (unsigned long)time2, startbuffer);
printf("diff time = %.2f\n", difftime(time2, time1));
return(0);
}
Sample output (from Mac OS X 10.7.5):
lt = 1358284665, t1 = 1358284665, time = 13:17:45
lt = 1358284675, t1 = 1358284675, time = 13:17:55
diff time = 10.00
I recommend looking at the values in your code, similar to the way I did. You might (or might not) print out the contents of the struct tm structures. It would be worth making a function to handle the 7-line block of repeated code; you'll need it to return time1 and time2, of course, so you can do the difference in the 'main' code. Also remember that localtime() may return the same pointer twice; you can't reliably use the start time structure after you've called localtime() with the finish time.