Reputation: 11
#include <stdio.h> /* puts */
#include <time.h> /* time_t, struct tm, time, localtime, strftime */
#include <bits/stdc++.h>
#include<unistd.h>
using namespace std;
int main ()
{
char CURRZONE[] = "TZ=Asia/Kolkata";
char DESTZONE[] = "TZ=UTC";
time_t stamp;
struct tm datetime;
putenv(CURRZONE);
char buffer[20];
uint16_t timevec[] = {15,28,12,30,06,2021};
datetime.tm_year = timevec[5]-1900;
datetime.tm_mon = timevec[4]-1;
datetime.tm_mday = timevec[3];
datetime.tm_hour = timevec[2];
datetime.tm_min = timevec[1];
datetime.tm_sec = timevec[0];
stamp = mktime(&datetime);
putenv(DESTZONE);
strftime (buffer,20,"%Y:%m:%d %T",localtime(&stamp));
std::string str(buffer);
cout<<str<<"\n";
return 0;
}
it's sometimes giving me the correct output which is 2021:06:30 06:58:15
othertimes it's giving me 1969:12:31 23:59:59
I don't need to compile the program again if I run it again its giving a different value. This behaviour is in CPP not with C. Not able to understand the reason behind the same.
Upvotes: 1
Views: 193
Reputation: 17413
The error can be reproduced reliably on a system using Glibc's implementation of mktime
by setting datetime.tm_isdst
to any positive value. That tells mktime
that DST is in effect for the supplied time information. That seems to be causing mktime
to return an error (return value (time_t)-1
with errno
set to EOVERFLOW
), perhaps because DST has not been in effect for Asia/Kolkata
since October 15, 1945 and mktime
has no idea what amount of DST correction should be applied. This is probably implementation-dependent1.
OP's code leaves datetime.tm_isdst
uninitialized, so the error occurs randomly (an example of undefined behavior). Setting datetime.tm_isdst
to 0 (meaning DST is not in effect) or a negative value (meaning mktime
should attempt to determine whether DST is in effect or not) prevents the error occuring.
POSIX (but not the C or C++ standards) requires mktime
to set errno
to indicate an error. That could be used to determine whether the return value of (time_t)-1
indicates an error or is an actual time value. By setting errno = 0;
before the call to mktime
and checking it afterwards, it can be used to confirm whether the return value of (time_t)-1
represents a genuinely unsuccessful result or not:
errno = 0;
stamp = mktime(&datetime);
if (stamp == (time_t)-1 && errno)
{
/* error */
}
else
{
/* OK */
}
(Note: it is important to use stamp == (time_t)-1
rather than stamp == -1
for portability reasons.)
1 The implementation of mktime
in the IANA tz distribution code does not return an error under the same conditions and applies a DST offset of 3600 seconds. Perhaps the Glibc implementation could be improved. It looks like the Glibc implementation of mktime
came from Gnulib, and that if there is a mismatch between the requested tm_isdst
value and the actual tm_isdst
value for the specified time, it will search neighboring transitions for a DST offset, but only within a range spanning 536454000 seconds (about 17 years) before and after the specified time. If no tm_isdst
match is found within that range, it gives up and returns an error with errno
set to EOVERFLOW
.
Upvotes: 4