将epoch之后的秒数转换为time_t

icnyk63a  于 2022-12-03  发布在  其他
关注(0)|答案(2)|浏览(188)

我有一个字符串表示自纪元以来的秒数,我需要将它转换为人类可读的字符串。我在网上看到一些帖子建议简单地将一个整数转换为time_t,如下所示:

time_t time = (time_t)(atoi(secs_since_epoch_str));

但是,如果我查找time_t的定义:

typedef /* unspecified */ time_t;

Although not defined by the C standard, this is almost always an integral 
value holding the number of seconds (not counting leap seconds) since 00:00,
Jan 1 1970 UTC, corresponding to POSIX time.

所以,这并不能保证一定能成功。我想知道是否有一个合适的方法来做这件事?

gpnt7bae

gpnt7bae1#

将 * 自epoch* 起的秒数转换为time_t
我有一个表示 seconds since epoch 的字符串,我需要将它转换为人类可读的字符串。
seconds 偏移量添加到epoch struct tm.tm_sec成员,形成time_t
1.将字符串转换为一个宽整数。(这里我假设字符串表示整数秒数。)它可能比long宽。为简洁起见,省略了错误处理。

long long offset = strtoll(string, NULL, 10);
    // or pedantically
    intmax_t offset = strtoimax(string, NULL, 10);

1.考虑time_t不一定是秒的计数(例如可能是纳秒),并且历元可能不是1970年1月1日的情况--这更有趣。

time_t epoch = 0;
    struct tm *tm_ptr = localtime(&epoch);
    if (tm_ptr == NULL) Handle_Error();
    struct tm tm = *tm_ptr;

1.添加到struct tm成员。可能将偏移量添加分段为多个部分以避免int溢出。当int为16位且offset较大(例如88年以上)时,需要更多代码。

tm.tm_sec += offset%60;
    offset /= 60;
    tm.tm_min += offset%60;
    offset /= 60;
    tm.tm_hour += offset%24;
    offset /= 24;
    tm.tm_mday += offset;

1.调用mktime()将时间戳带入主范围并打印。请注意,由于time_t可能是某种整数类型或浮点类型,因此转换为FP类型进行打印。

time_t target = mktime(&tm);
    printf("%Lg\n", (long double) target);
    if (target == -1) Handle_Error();
    printf("%s", asctime(&tm));
0kjbasz6

0kjbasz62#

所以,这并不能保证一定能成功。我想知道是否有一个合适的方法来做这件事?
嗯......我不太明白你的意思。time_t是一个特定于unix的类型,它已经发展成为POSIX标准。如果你收到的是一个字符串,那么你必须处理它是一个64位数字的可能性(例如FreeBSD使用64位time_t
关于纪元时间,它并不总是那个纪元(unix的第一个版本使用01.01.1972,但我想我们没有人见过这样的系统---我在家里运行一个用于pdp-11的unix v7,它有一个32位时间---当时没有time_t类型,它是一个long int---它是基于实际的纪元时间)
您必须小心,因为从概念开始,unix time就一直是一个 signed 值,因此它从1970-01-01开始,但是您可以指定日期早于,只要使用负值即可,如下所示:

$ LANG=C date -u -r -2147483648
Fri Dec 13 20:45:52 UTC 1901
$ _

这就是为什么它会在

$ LANG=C date -u -r 2147483647
Tue Jan 19 03:14:07 UTC 2038
$ _

另一方面,您的问题是不明确的,因为您没有说明最终的字符串数据必须转换到哪个地区和时区(或格式)。最好的方法是使用标准的unix时间函数(查找gmtime(3)localtime(3)struct tm关联类型)
一种常见的做法是:

time_t now = time(NULL);
    struct tm *now_gmt = gmtime(&now);

然后,如果您对时间的特定格式不感兴趣,请用途:

printf("%s", asctime(now_gmt));

或者,您也可以对struct tm字段(tm_yeartm_montm_mdaytm_hourtm_mintm_sectm_wdaytm_ydaytm_isdst--最后一个字段用于了解您是在冬季还是夏季)进行操作
所以一切都在POSIX中解决了。
最后,如果要将一个很大的数字(对于64位值)转换为time_t,最好的方法是使用以下公式进行转换:

#include <stdint.h>

...

    int64_t val;

    sscanf(the_string_value, "%lld", &val); /* use a 64bit type */
    time_t my_time_t = (time_t) val; /* then cast it to time_t */

(我使用了强制类型转换,因为time_t可以小于int64_t,这样可以避免编译器发出警告)
这将适用于64位和32位整数。一旦您将其转换为time_t,以上所有内容仍然有效。

相关问题