mktime adds hour unless extra timespec pointers declared
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
mktime adds hour unless extra timespec pointers declared
I have a set of applications which convert ascii (YYYY-MM-DD) style time to unix time (time_t), and vice-versa. I was getting unexpected results so I put together a little test application which converts ascii string time (from the command line) to a tm struct, back again tm -> ascii (so far, so good), then into time_t calendar representation using mktime(). Here is where it breaks down. The time returned from mktime is an hour ahead. HOWEVER, by dumb luck I found that if I declare (but don't use) not one but two pointers to a timespec struct, then mktime returns the correct time.
What is happening there?
A copy of the test code is below.
Thanks.
Code:
/* timetest.c
* ----------
* compile with gcc -lrt -o timetest timetest.c
*
* d.hale, 2010-05-05
*
* call with YYYYMMDDTHHMMSS (e.g. timetest 20100505T120000)
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
int main(int argc, char **argv)
{
/* !!! uncomment this line to make it report the correct time !!!
struct timespec *p, *q;
*/
struct timespec ts;
time_t t;
struct tm tm, *gmt;
const char fm[]="%Y%m%dT%H%M%S";
char buf[256];
if (argc>1) {
printf("\n argv=%s\n", argv[1]);
strptime(argv[1], fm, &tm); /* convert argv string to tm struct */
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm); /* and back again */
printf(" argv=%s (converted strptime->strftime)\n",buf);
t = mktime(&tm); /* now convert to calendar representation */
/* !!! The incorrect time will be reported here,
!!! unless the *p, *q line is uncommented above */
printf(" argv tm=%d ==> %d-%02d-%02d %02d:%02d:%02d (dst=%d)\n", t,
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_isdst);
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
printf(" %s (converted mktime->strftime)\n",buf);
gmt = gmtime(&t); /* this is also wrong */
printf("argv gmt=%d-%02d-%02d %02d:%02d:%02d\n", gmt->tm_year+1900,
gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
printf(" asctime=%s\n", asctime(&tm));
}
clock_gettime(CLOCK_REALTIME, &ts);
printf("timespec now = %d.%09d\n", ts.tv_sec, ts.tv_nsec);
return 0;
}
Last edited by halestorm914; 05-06-2010 at 02:09 PM.
First, I was able to reproduce the problem, even when uncommenting the declarations of p and q.
The problem boils down to strptime() not filling in the tm_isdst field of the struct. After I made a few changes to your source, the following script ...
##############################################################################
cat timetest.c
/* timetest.c
* ----------
* compile with gcc -lrt -o timetest timetest.c
*
* d.hale, 2010-05-05
*
* call with YYYYMMDDTHHMMSS (e.g. timetest 20100505T120000)
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
int main(int argc, char **argv)
{
struct timespec *p, *q;
struct timespec ts;
time_t t;
struct tm tm, *gmt;
const char fm[]="%Y%m%dT%H%M%S";
char buf[256];
if (argc>1) {
printf("\n argv=%s\n", argv[1]);
strptime(argv[1], fm, &tm); /* convert argv string to tm struct */
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm); /* and back again */
printf(" argv=%s (converted strptime->strftime)\n",buf);
printf("There's your trouble -> %d-%02d-%02d %02d:%02d:%02d (dst=%d)\n",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_isdst);
t = mktime(&tm); /* now convert to calendar representation */
/* !!! The incorrect time will be reported here,
!!! unless the *p, *q line is uncommented above */
printf(" argv tm=%d ==> %d-%02d-%02d %02d:%02d:%02d (dst=%d)\n", t,
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_isdst);
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
printf(" %s (converted mktime->strftime)\n",buf);
gmt = gmtime(&t); /* this is also wrong */
printf("argv gmt=%d-%02d-%02d %02d:%02d:%02d\n", gmt->tm_year+1900,
gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
printf(" asctime=%s\n", asctime(&tm));
}
clock_gettime(CLOCK_REALTIME, &ts);
printf("timespec now = %d.%09d\n", ts.tv_sec, ts.tv_nsec);
return 0;
}
##############################################################################
gcc -lrt -o timetest timetest.c
timetest 20100505T120000
argv=20100505T120000
argv=20100505T120000 (converted strptime->strftime)
There's your trouble -> 2010-05-05 12:00:00 (dst=0)
argv tm=1273089600 ==> 2010-05-05 13:00:00 (dst=1)
20100505T130000 (converted mktime->strftime)
argv gmt=2010-05-05 20:00:00
asctime=Wed May 5 13:00:00 2010
timespec now = 1273241321.034025332
What to do? Well, I hope someone can come along and recommend something more constructive than the following, but I've long been dissatisfied with all but the most trivial provided time conversion functions. I just go to the data source:
Code:
/usr/share/zoneinfo
and do my own conversions as I need them. For more info:
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.