Camden Narzt
Camden Narzt

Reputation: 2003

Am I using tm/mktime wrong, and if not is there a workaround?

I think the following program should output the seconds to 1970 for the first day of every year from 1AD to 1970, preceded by the size of time_t on the system it's compiled on (CHAR_BIT is a macro so I think you can't just copy the compiled executable around and assume it's correct though in practice everything uses 8 bit chars these days).

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

void do_time(int year)
{
  time_t utc;
  struct tm tp;

  memset(&tp, 0, sizeof(tp));

  tp.tm_sec = 0;
  tp.tm_min = 0;
  tp.tm_hour = 0;
  tp.tm_mday = 1;
  tp.tm_mon = 0;
  tp.tm_year = year - 1900;
  tp.tm_wday = 1;
  tp.tm_yday = 0;
  tp.tm_isdst = -1;

  printf("%d %ld\n",year, mktime(&tp));
}

int main(){
  printf("time_t is %lu bits\n",sizeof(time_t)*CHAR_BIT);
  for (int i = 1; i<1971; i++)
    do_time(i);
  exit(0);
}

However on OS X (10.11.3 15D21) this only works for years >= 1902, despite time_t being 64 bit signed. I could potentially understand if the programmers at Apple were lazy and didn't support any years before 1970, but correct behaviour going back to 1902 and then stopping looks more like an error on my part.

Upvotes: 4

Views: 714

Answers (2)

Daniel Jour
Daniel Jour

Reputation: 16156

Consulting the C standard:

The range and precision of times representable in clock_t and time_t are implementation-defined. [..]

[N1570 §7.27.1/4] (emphasis mine)

And further down, regarding mktime:

The mktime function returns the specified calendar time encoded as a value of type time_t. If the calendar time cannot be represented, the function returns the value (time_t)(-1).

[N1570 §7.27.2.3/3]

As such, as long as the return value of mktime is (time_t)(-1) for the years where it's not working ... you're on your own.


Actually, IMO, the standard is a bit quiet about all of this:

[..] int tm_year; // years since 1900 [..]

[N1570 §7.27.1/4]

This could mean (positive) years since 1900, but then why use a signed integer.


As a side note: On my system (Linux 3.14.40 x86_64 glibc-2.21), I get ...

time_t is 64 bits
1 -62135600008
...
1969 -31539600
1970 -3600

Considering the work around part: You can of course look at libc implementations that are doing what you want and try to use their code (if that's possible with respect to any licences you need to obey). Here's the one my system uses.

Upvotes: 4

Kurt Stutsman
Kurt Stutsman

Reputation: 4034

In UNIX OS there are often 64 bit-enabled versions of time functions. OS X may have something similar though I couldn't find it with my quick searching. See 64 bit unix timestamp conversion for more information.

EDIT: I found a Mac to test this on and it does not appear to have a mktime64 function unfortunately. I did find this this library that might work as a work-around though I haven't tested it personally.

Upvotes: 0

Related Questions