简体   繁体   English

人类可读的64位time_t值字符串

[英]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(&current_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(&current_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() or ctime_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 2147485547 ctime 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM