我使用tm/mktime是否错误,是否没有解决方法?
我认为以下程序应将每年的第一天从1AD到1970的秒数输出到1970,在其编译的系统上,time_t
的大小在其前面(CHAR_BIT
是宏,所以我认为您不能只是复制编译后的可执行文件并假设它是正确的,尽管实际上在今天,所有东西都使用8位char
.
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 char
s 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);
}
但是,在OS X(10.11.3 15D21)上,即使time_t
被64位签名,它也只能在> = 1902年使用.我可能理解苹果的程序员是否懒惰并且在1970年之前没有任何支持,但是正确的行为可以追溯到1902年,然后停止,这更像是我的错误.
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.
咨询C标准:
在
clock_t
和time_t
中可以表示的范围和时间精度为 实现定义的. [..]
The range and precision of times representable in
clock_t
andtime_t
are implementation-defined. [..]
[N1570§7.27.1/4](强调我的意思)
[N1570 §7.27.1/4] (emphasis mine)
再往下讲,关于mktime
:
mktime
函数返回指定的日历时间,该时间编码为type的值time_t
.如果无法表示日历时间,则该函数返回值(time_t)(-1)
.
The
mktime
function returns the specified calendar time encoded as a value of typetime_t
. If the calendar time cannot be represented, the function returns the value(time_t)(-1)
.
[N1570§7.27.2.3/3]
[N1570 §7.27.2.3/3]
这样,只要mktime
的返回值在不起作用的年份中为(time_t)(-1)
,您就可以靠自己了.
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.
实际上,IMO,所有这些标准都比较安静:
Actually, IMO, the standard is a bit quiet about all of this:
[..]
int tm_year; // years since 1900
[..]
[N1570§7.27.1/4]
[N1570 §7.27.1/4]
这可能意味着自1900年以来的(正)年,但是为什么要使用带符号整数.
This could mean (positive) years since 1900, but then why use a signed integer.
作为旁注:在我的系统(Linux 3.14.40 x86_64 glibc-2.21)上,我得到...
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
考虑到周围的工作:当然,您可以查看正在执行所需操作的libc实现,并尝试使用其代码(如果您需要遵守的任何许可,如果可以的话).
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.