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

落花浮王杯 提交于 2020-01-04 03:54:25

问题


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.


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/35300453/am-i-using-tm-mktime-wrong-and-if-not-is-there-a-workaround

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!