Hi,

[Posting here because I think there is a potential manual
improvement in this puzzle, which I will be happy to write up once
I figure it out.]

I'm trying to figure out how to convert a string to seconds since epoch
in the local timezone.

When I use strptime() and mktime(), I get a result that is one hour off.

My best guess is that mktime() expects tm_isdst but strptime() doesn't
load it.  But I don't know how to work around this.

Or am I missing something else?

Below is a short program that demonstrates the behavior and it's output.

Thanks for any help,

m

$ ./a.out
date -j 200810140806.21 +%s returns 1223985981
a.out: tm.tm_sec    = 21
a.out: tm.tm_min    = 6
a.out: tm.tm_hour   = 8
a.out: tm.tm_mday   = 14
a.out: tm.tm_mon    = 9
a.out: tm.tm_year   = 108
a.out: tm.tm_wday   = 0
a.out: tm.tm_yday   = 0
a.out: tm.tm_isdst  = 0
a.out: tm.tm_zone   = (null)
a.out: tm.tm_gmtoff = 0
exp 1223985981, got 1223989581: delta = -3600
$



#include <sys/types.h>
#include <sys/wait.h>

#include <limits.h>
#include <err.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define EXITOK(rc)      (WIFEXITED(rc) && WEXITSTATUS(rc) == 0)

static char *time_s    = "2008-10-14 08:06:21";
static char *time_s_v2 = "200810140806.21";
static char *fmt    = "%Y-%m-%d %H:%M:%S";

/* Return seconds since epoch computed using the date utility. */
time_t
expected()
{
        char             cmd[500] = {0};
        char             outbuf[4096];
        unsigned long    exp, act;
        int              rc;
        FILE            *pfp;

        /* date -j 200810140806.21 +%s */
        (void) snprintf(cmd, sizeof(cmd),
            "date -j %s +%%s", time_s_v2);

        if ((pfp = popen(cmd, "r")) == NULL)
                errx(1, "popen failed.");
        while (fgets(outbuf, sizeof(outbuf), pfp) != NULL)
                printf("%s returns %s", cmd, outbuf);
        if((rc = pclose(pfp)) == -1)
                errx(1, "pclose returns -1");
        if (!EXITOK(rc))
                errx(1, "%s didn't terminate normally", cmd);

        return (time_t) strtoul(outbuf, 0, 10);
}

/* Returns seconds since epoch using strptime() and mktime() */
time_t
actual()
{
        struct tm       tm;
        time_t           rval;

        rval = (time_t) 0;

        memset(&tm, 0, sizeof(tm));
        if (strptime(time_s, fmt, &tm) == NULL)
                errx(1, "fmt '%s' didn't match '%s'", fmt, time_s);

        warnx("tm.tm_sec    = %d", tm.tm_sec);
        warnx("tm.tm_min    = %d", tm.tm_min);
        warnx("tm.tm_hour   = %d", tm.tm_hour);
        warnx("tm.tm_mday   = %d", tm.tm_mday);
        warnx("tm.tm_mon    = %d", tm.tm_mon);
        warnx("tm.tm_year   = %d", tm.tm_year);
        warnx("tm.tm_wday   = %d", tm.tm_wday);
        warnx("tm.tm_yday   = %d", tm.tm_yday);
        warnx("tm.tm_isdst  = %d", tm.tm_isdst);
        warnx("tm.tm_zone   = %s", tm.tm_zone);
        warnx("tm.tm_gmtoff = %lu", tm.tm_gmtoff);

        return mktime(&tm);
}

int
main(void)
{
        time_t  act, exp;
        double  delta;

        exp = expected();
        act = actual();

        delta = difftime(exp, act);
        if (fabs(delta) > DBL_EPSILON) {
                printf("exp %llu, got %llu: delta = %.0f\n",
                    (long long int) exp, (long long int) act,
                    delta);
                return 1;
        }
        else
                return 0;

}

Reply via email to