anon
anon

Reputation:

ctime gives incorrect output

ctime() function is supposed to give the time in string format since Epoch for the seconds passed in. This is my code:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int main(int argc, int **argv)
{
    time_t tmp=86400; // Seconds for one day
    char *s;
    s = ctime(&tmp);
    if(!s) perror("ctime");
    else printf("%s", s);
    return 0;
}

The program gives correct output on my Ubuntu 12.04, 32 bit machine:

Fri Jan  2 01:00:00 1970

But the same code gives wrong output on my Scientific Linux, 64-bit machine:

Thu Jan  1 16:00:00 1970

Apparently, according to this machine Epoch is:

Wed Dec 31 16:00:00 1969

Any idea why Scientific Linux 6 is giving wrong output?!

Upvotes: 2

Views: 5668

Answers (3)

Keith Thompson
Keith Thompson

Reputation: 263197

A time_t value always [1] represents the number of seconds since the epoch, which is 1970-01-01 00:00:00 UTC -- plus or minus whatever handwaving is required to acknowledge that we're probably ignoring leap seconds. So (time_t)86400 represents a single moment in time, regardless of your current time zone.

The ctime() function returns a pointer to an awkwardly formatted[2] string expressed in local time. I'm 8 hours west of UTC, so on my system your program's output is:

Thu Jan  1 16:00:00 1970

(the epoch plus 24 hours from your 86400, minus 8 hours for my time zone).

A system's idea of the current time zone can be determined in any of several ways. On my Ubuntu system, /etc/timezone contains the line America/Los_Angeles. On CentOS, which should be similar to Scientific Linux, /etc/localtime is a binary timezone data file.

On both systems, the system default time zone can be overridden by setting the $TZ environment variable, with UTC or the empty string denoting UTC. If I set $TZ to either UTC or "", your program's output is:

Fri Jan  2 00:00:00 1970

The epoch is always the same moment in history, but it can be expressed differently. For example (using the GNU Coreutils date command, showing the epoch itself rather than 24 hours after the epoch as your program does):

$ date -d @0
Wed Dec 31 16:00:00 PST 1969
$ date -u -d @0
Thu Jan  1 00:00:00 UTC 1970
$ TZ=UTC date -d @0
Thu Jan  1 00:00:00 UTC 1970
$ TZ= date -d @0
Thu Jan  1 00:00:00 UTC 1970
$ 

Note that if you're in the UK, your local time matches UTC only part of the year.

[1] Well, nearly always. POSIX guarantees that a time_t value represents seconds since the epoch, but the C standard says only that it's an arithmetic type capable of representing times. And you can store any value you like in a time_t object, and have it mean whatever you like, but all the standard C and POSIX functions that deal with time_t values treat them as seconds since the epoch.

[2] The format produced by ctime() and asctime() is rather awkward, for historical reasons. It's of the form Sun Sep 16 01:03:52 1973\n\0. Note the lack of any time zone information; also the trailing '\n' can be confusing (I've seen extraneous blank lines in log files because of it). The strftime() function gives you a lot more flexibility. I recommend using ISO 8601 format wherever possible.

Upvotes: 4

fvu
fvu

Reputation: 32953

The manual page you refer to says

The ctime(), gmtime() and localtime() functions all take an argument of data type time_t which represents calendar time. When interpreted as an absolute time value, it represents the number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).

And this some ctime implementation

char *
ctime(timep)
const time_t * const    timep;
{
    return asctime(localtime(timep));
}

As you can see, it uses localtime, ie time relative to timezone of the current process.

Upvotes: 1

Forhad Ahmed
Forhad Ahmed

Reputation: 1771

the number of seconds should be in UTC - number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC

Look at the description for time_t:

http://www.cplusplus.com/reference/ctime/time_t/

Upvotes: 1

Related Questions