2

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;

}
tanvi rustagi
  • 21
  • 1
  • 2
  • 1
    There are not only tm_min and tm_hour in a tm structure. See here: http://www.cplusplus.com/reference/ctime/tm/ – leyanpan Dec 22 '17 at 08:58
  • i modified the code by adding this : struct tm DateTimeUtils::makeTime(string arrTime) { struct tm neww; neww.tm_sec=0-61; neww.tm_mday=1-31; neww.tm_mon=0-11; neww.tm_year=1900; neww.tm_wday=0-6; neww.tm_yday=0-365; string hour = arrTime.substr(0,2); int hour_int = stoi(hour); neww.tm_hour=hour_int; string minute = arrTime.substr(2,2); int minute_int = stoi(minute); neww.tm_min=(minute_int); time_t t1 = mktime(&neww); cout< – tanvi rustagi Dec 22 '17 at 09:03
  • *"i modified the code..."* - great. now [modify your question](https://stackoverflow.com/posts/47938426/edit) to include an *addendum* with your changes. Walls of code won't belong in comments; they belong in the posted question, and ideally, they're minimized to exhibit only the problem to which your question pertains. – WhozCraig Dec 22 '17 at 10:04

3 Answers3

1

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;
}
Community
  • 1
  • 1
Drax
  • 12,682
  • 7
  • 45
  • 85
  • `time_t` in most implementations is `long int`, which is an signed integer type. Therefore it is capable of having the same range in positive and negative values which is(on a 32 bit machine) roughly from -291 bilion years to +291 bilion years. – Detonar Dec 22 '17 at 11:23
  • Note that `mktime()` is time-zone sensitive: Supplying `1970-01-01T00:00` won't yield `mktime(...) == 0` in most places of the world. So you would need to add the seconds/minutes/hours to the values you get out of the `localtime()` call, instead of just overwriting those values. – cmaster - reinstate monica Dec 22 '17 at 11:55
  • @Detonar 32 bit can represent 2^32 = 4294967296, there is approximately 31536000 seconds in a year. 4294967296 / 31536000 = 136. So actually you can represent 136 years, not billions of years. But for some reason on my machine mktime fails if i go above 68 years, which seems to be half of that theorical limit, not sure why though. – Drax Dec 22 '17 at 11:58
  • @Drax a `long int` on an 32 bit system represents 64 bit meaning from -2^63 to +2^63-1 which is -9223372036854775808 to +9223372036854775807 seconds... And even if it were just a simple `int` it would be more than that 70 years difference you mentioned. – Detonar Dec 22 '17 at 12:10
  • Well, if it were just a simple `int` that would explain it because `int` IS signed. But that would be weird. – Detonar Dec 22 '17 at 12:18
  • @Detonar You are right, i can't seem to explain the practical behaviour i see on my machine with theoretical size limits. It might just be a hard coded limit of mktime on some platforms. I do still notice that if you go under that amount everything works fine so the answer is still valid. – Drax Dec 22 '17 at 14:29
0

Clearing the struct before usage usually helps in this case:

struct tm neww;
memset((void *)&neww, 0, sizeof(tm));
Anton Malyshev
  • 8,686
  • 2
  • 27
  • 45
  • still returning -1! – tanvi rustagi Dec 22 '17 at 09:28
  • Then check what exact values are you passing. Maybe you passed wrong values like hour=30, minute=100 etc. Also what is `neww.tm_mday=1-31`? Are you passing -30? – Anton Malyshev Dec 22 '17 at 09:31
  • neww.tm_sec=60; neww.tm_mday=1; neww.tm_mon=11; neww.tm_year=1900; neww.tm_wday=6; neww.tm_yday=365; – tanvi rustagi Dec 22 '17 at 09:34
  • At least you can have conflicting day settings: tm_mday, tm_wday and tm_yday, specify just one of them. Also year=1900 is 1900+1900, see http://www.cplusplus.com/reference/ctime/tm/ – Anton Malyshev Dec 22 '17 at 09:40
  • struct tm DateTimeUtils::makeTime(string arrTime) { struct tm neww; memset((void *)&neww, 0, sizeof(tm)); neww.tm_sec=1; neww.tm_mday=1; neww.tm_mon=1; neww.tm_year=0; string hour = arrTime.substr(0,2); int hour_int = stoi(hour); neww.tm_hour=hour_int; string minute = arrTime.substr(2,2); int minute_int = stoi(minute); neww.tm_min=(minute_int); time_t t1 = mktime(&neww); cout< – tanvi rustagi Dec 22 '17 at 09:43
  • @tanvi rustagi - `neww.tm_sec=60` looks critical. try to avoid this. – Detonar Dec 22 '17 at 09:43
  • @Detonar yes i changed the values to :neww.tm_sec=1; neww.tm_mday=1; neww.tm_mon=1; neww.tm_year=0; – tanvi rustagi Dec 22 '17 at 09:45
  • and what is `tm_hour`? – Anton Malyshev Dec 22 '17 at 09:46
  • i'm reading that from a file which are values between 1 to 24... cout< – tanvi rustagi Dec 22 '17 at 09:52
  • @tanvirustagi I cannot reproduce your problem. The code `#include #include int main() { struct tm date = { .tm_sec = 60, .tm_mday = 1, .tm_mon = 11, .tm_year = 1900, .tm_wday = 6, .tm_yday = 365 }; time_t result = mktime(&date); printf("result = %lld\n", (long long)result); }` does not print `-1`. – cmaster - reinstate monica Dec 22 '17 at 11:35
0

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
Detonar
  • 1,409
  • 6
  • 18