[英]Human readable string of 64bits time_t value
I'm trying to print out the date, in a human readable format, for the maximum time_t value possible. 我正在尝试以人类可读的格式打印日期,以获取最大的time_t值。 The following code seems to work just fine on 32bits machines (initializing m_time with 0x7fffffff), but it outputs null for the theoretically highest value on a 64bits machine.
以下代码似乎在32位计算机上正常工作(用0x7fffffff初始化m_time),但对于64位计算机上的理论上的最大值,它输出null。 Is that a ctime limitation or am I missing something?
那是ctime的限制,还是我缺少什么?
compilation : gcc -Wall -g3 main.c -o time_test 编译:gcc -Wall -g3 main.c -o time_test
host machine: x86_64. 主机:x86_64。
#include <stdio.h>
#include <time.h>
#include <stddef.h>
int main(int argc, char** argv) {
time_t m_time = 0x7fffffffffffffff;
time_t current_time;
time(¤t_time);
printf("time_t info: sizeof [%ld] bytes or [%ld] bits.\n", sizeof(time_t), sizeof(time_t) *8 );
printf("m_time val: [%ld]-> %s\n", m_time, ctime(&m_time));
printf("current_time val: [%ld]-> %s\n", current_time, ctime(¤t_time));
return 0;
}
Output: 输出:
time_t info: sizeof [8] bytes or [64] bits.
m_time val: [9223372036854775807]-> (null)
current_time val: [1430678274]-> Sun May 3 15:37:54 2015
tks. 韩国社交协会。
BTW, ctime (& ctime(3) ) is documented as giving a string with the year represented by four digits (for a total of 26 bytes). 顺便说一句, ctime (& ctime(3) )被记录为给出一个字符串,其中年份用四个数字表示(总共26个字节)。 So the maximal time is in the year 9999 (certainly less than maximal
time_t
on a machine with 64 bits time_t
). 所以,最大的时间是在9999年(肯定比少最大
time_t
一台机器上有64位time_t
)。
Also (as I commented), pragmatically, if time_t
has more than 40 bits (eg 64 bits) you don't care about the maximally representable time. 同样(如我所评论),从实用的角度来说,如果
time_t
位数超过40位(例如64位),则您无需考虑最大可表示时间。 You and everyone reading that forum (and all our grand grand children) would be dead, the computers running your program will all be destroyed, and at that time C won't exist anymore. 您和在该论坛上阅读的每个人(以及我们所有的大孙子)都会死掉,运行您程序的计算机都将被销毁,到那时C将不再存在。 The Y2038 problem don't practically have any 64 bits equivalent.
Y2038问题实际上没有任何64位等效项。 So just special case when
time_t
is 32 bits. 因此,仅在
time_t
为32位时的特殊情况。
It is very unlikely than any C program would matter after the year 3000; 3000年以后,几乎没有什么C程序会如此重要; software, hardware, standards, and human technical expertise don't last that long...
软件,硬件,标准和人类技术专长不会持续那么长时间...
The POSIX ctime documentation says explicitly : POSIX ctime文档 明确指出 :
Attempts to use
ctime()
orctime_r()
for times before the Epoch or for times beyond the year 9999 produce undefined results .尝试在时代之前或9999年以后使用
ctime()
或ctime_r()
产生不确定的结果 。 Refer to asctime .请参阅asctime 。
BTW, musl-libc seems to be conformant to the standard: its time/__asctime.c
(indirectly called by ctime
) has a nice comment: 顺便说一句, musl-libc似乎符合该标准: 它的
time/__asctime.c
(由ctime
间接调用)有一个很好的注释:
if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
__nl_langinfo(ABDAY_1+tm->tm_wday),
__nl_langinfo(ABMON_1+tm->tm_mon),
tm->tm_mday, tm->tm_hour,
tm->tm_min, tm->tm_sec,
1900 + tm->tm_year) >= 26)
{
/* ISO C requires us to use the above format string,
* even if it will not fit in the buffer. Thus asctime_r
* is _supposed_ to crash if the fields in tm are too large.
* We follow this behavior and crash "gracefully" to warn
* application developers that they may not be so lucky
* on other implementations (e.g. stack smashing..).
*/
a_crash();
}
and GNU glibc
has in its time/asctime.c file: GNU
glibc
在其time / asctime.c文件中具有:
/* We limit the size of the year which can be printed. Using the %d
format specifier used the addition of 1900 would overflow the
number and a negative vaue is printed. For some architectures we
could in theory use %ld or an evern larger integer format but
this would mean the output needs more space. This would not be a
problem if the 'asctime_r' interface would be defined sanely and
a buffer size would be passed. */
if (__glibc_unlikely (tp->tm_year > INT_MAX - 1900))
{
eoverflow:
__set_errno (EOVERFLOW);
return NULL;
}
int n = __snprintf (buf, buflen, format,
(tp->tm_wday < 0 || tp->tm_wday >= 7 ?
"???" : ab_day_name (tp->tm_wday)),
(tp->tm_mon < 0 || tp->tm_mon >= 12 ?
"???" : ab_month_name (tp->tm_mon)),
tp->tm_mday, tp->tm_hour, tp->tm_min,
tp->tm_sec, 1900 + tp->tm_year);
if (n < 0)
return NULL;
if (n >= buflen)
goto eoverflow;
So I believe that both GNU glibc and musl-libc are better than MacOSX implementation (as cited in zneak's answer ) on that aspect. 因此,我认为在这方面,GNU glibc和musl-libc都比MacOSX实现(如zneak的答案中引用) 要好 。 The standards requires
ctime
to give 26 bytes. 该标准要求
ctime
提供26个字节。 Also, POSIX 2008 is marking ctime
as obsolete , new code should use strftime (see also strftime(3) ). 另外, POSIX 2008将
ctime
标记为过时的 ,新代码应使用strftime (另请参见strftime(3) )。
To get to the bottom of this, the best idea is to find an implementation and look at what it does. 归根结底,最好的主意是找到一个实现并查看它的作用。 I downloaded Apple's
Libc
tarball for OS X 10.1.1 (whose link can be found on this page ), and found that ctime
is defined in stdtime/FreeBSD/localtime.c. 我下载了OS X 10.1.1的 Apple
Libc
tarball (可在此页面上找到其链接),并发现ctime
在stdtime / FreeBSD / localtime.c中定义。
The function goes like this: 该函数如下所示:
char *
ctime(timep)
const time_t * const timep;
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
** The ctime function converts the calendar time pointed to by timer
** to local time in the form of a string. It is equivalent to
** asctime(localtime(timer))
*/
#ifdef __LP64__
/*
* In 64-bit, the timep value may produce a time value with a year
* that exceeds 32-bits in size (won't fit in struct tm), so localtime
* will return NULL.
*/
struct tm *tm = localtime(timep);
if (tm == NULL)
return NULL;
return asctime(tm);
#else /* !__LP64__ */
return asctime(localtime(timep));
#endif /* __LP64__ */
}
From a second-hand reference , struct tm
appears to be defined in terms of integers, and the tm_year
field is an offset from 1900. Assuming conformance to that, even a non-conforming ctime
cannot possibly accept a timestamp after year 2 31 +1900-1. 从二手参考来看,
struct tm
似乎是用整数定义的,并且tm_year
字段是从1900开始的偏移量。假设与此相符,则即使不符合标准的ctime
也可能无法接受2 31 + 1900年之后的时间戳记-1。
Here is a program that finds (and tests) the largest timestamp ctime
will accept with Apple's implementation: 这是一个程序,该程序查找(并测试)
ctime
在Apple的实现中将接受的最大时间戳:
#include <limits.h>
#include <stdio.h>
#include <time.h>
int main(int argc, char** argv) {
struct tm t = {
.tm_sec = 59,
.tm_min = 59,
.tm_hour = 23,
.tm_mday = 31,
.tm_mon = 11,
.tm_year = INT_MAX,
};
time_t max = mktime(&t);
printf("Maximum time: %li\n", max);
printf("ctime max: %s\n", ctime(&max));
max++;
printf("ctime max+1: %s\n", ctime(&max));
}
Output: 输出:
Maximum time: 67768036191694799
最长时间:67768036191694799
ctime max: Wed Dec 31 23:59:59 2147485547ctime max:周三12月31日23:59:59 2147485547
ctime max+1: (null)ctime max + 1 :(空)
This is a 56-bit number, so the maximum year a 64-bit time_t
can hold (though struct tm
can't) is probably between 547,608,814,485 and 549,756,300,032, or like 36 times the age of the universe. 这是一个56位的数字,因此64位的
time_t
可以保存的最大年份(尽管struct tm
不能保存)可能在547,608,814,485和549,756,300,032之间,或者是宇宙年龄的36倍。 In other words, it's going to be a while. 换句话说,这将需要一段时间。
For what it's worth, Apple's implementation is not conforming. 就其价值而言,苹果的实施方式并不符合标准。 The standard says that the output of
ctime
has to fit inside 26 bytes, including a newline character and a null character. 该标准说,
ctime
的输出必须容纳26个字节,包括换行符和空字符。 For a conforming implementation, this means that the year has to be within -999 and 9999. 对于符合标准的实施,这意味着年份必须在-999到9999之间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.