16

如何__TIMESTAMP__在 ISO 8601:2004 中进行替换?

__TIMESTAMP__

Sat Jul  6 02:50:06 2013

对比

__TIMESTAMP_ISO__

2013-07-06T00:50:06Z
4

5 回答 5

21

哦,你这个乐观主义者!您不会真的期望一个标准关注另一个标准,对吗?__TIMESTAMP__正如您所知,该定义不在标准 C 中。有一个像你提议的格式会很棒__TIMESTAMP_ISO__(你总是想要祖鲁时间,还是让本地时区偏移更好?),但坦率地说,添加它的最简单方法可能是 GCC 的补丁和 Clang 等等。

您可以按照user1034749回答asctime()的建议尝试使用猴子,但我宁愿不尝试。

在 GCC 4.8.1手册中,有一个有趣的警告抑制:

-Wno-builtin-macro-redefined
如果某些内置宏被重新定义,则不要发出警告。这将禁止重新定义__TIMESTAMP____TIME____DATE____FILE__和 的警告__BASE_FILE__

这建议您可以尝试:

gcc ... -Wno-builtin-macro-redefined -D__TIMESTAMP__=$(date +'"%Y-%m-%dT%H:%M:%S"') ...

(注意从双引号中获取字符串所必需的象形文字date。)但是,一些早期版本的 GCC 不支持该选项。我不记得以前见过它。您仍然可以重新定义__TIMESTAMP__

$ gcc -std=c99   -Wall -Wextra  -O xx.c -o xx
$ ./xx 
Fri Jul  5 19:56:25 2013
$ gcc -std=c99 -Wall -Wextra -D__TIMESTAMP__=$(date +'"%Y-%m-%dT%H:%M:%S"') -O xx.c -o xx  
<command-line>: warning: "__TIMESTAMP__" redefined
$ ./xx
2013-07-05T20:10:28
$

不是很漂亮,但它可以工作......哦,只是为了记录,源代码是(微不足道的):

#include <stdio.h>

int main(void)
{
    printf("%s\n", __TIMESTAMP__);
    return 0;
}
于 2013-07-06T03:12:59.720 回答
4

@Jonathan Leffler 的回答提供了一个很好的解决方案,但可能有一件事被忽略了:
最初的问题是询问__TIMESTAMP__while的替代格式__TIMESTAMP__是要扩展到当前源文件的最后修改日期时间字符串。然而,最初的答案实际上是分配__TIMESTAMP__运行 gcc 的日期时间(即构建时间),它作为__DATE__and工作__TIME__

如何改进
使用@mmond 的答案,用替换date +'"%Y-%m-%dT%H:%M:%S"'命令,即在运行命令时添加选项以引用xx.c。xx.c是正在构建的源代码-D__TIMESTAMP__=...date +'"%Y-%m-%dT%H:%M:%S"' -r xx.c-r xx.cdate

参考:
根据 GCC 的[manual][2]

__TIMESTAMP__
此宏扩展为一个字符串常量,描述当前源文件的最后修改日期和时间。

于 2018-06-29T06:35:23.790 回答
1

这是一种定义包含编译时间戳的日期部分的字符串常量的方法。将时间部分添加到它并不难,并使其工作__TIMESTAMP__而不是__DATE__.

constexpr unsigned int compileYear = (__DATE__[7] - '0') * 1000 + (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0');
constexpr unsigned int compileMonth = (__DATE__[0] == 'J') ? ((__DATE__[1] == 'a') ? 1 : ((__DATE__[2] == 'n') ? 6 : 7))    // Jan, Jun or Jul
                                : (__DATE__[0] == 'F') ? 2                                                              // Feb
                                : (__DATE__[0] == 'M') ? ((__DATE__[2] == 'r') ? 3 : 5)                                 // Mar or May
                                : (__DATE__[0] == 'A') ? ((__DATE__[2] == 'p') ? 4 : 8)                                 // Apr or Aug
                                : (__DATE__[0] == 'S') ? 9                                                              // Sep
                                : (__DATE__[0] == 'O') ? 10                                                             // Oct
                                : (__DATE__[0] == 'N') ? 11                                                             // Nov
                                : (__DATE__[0] == 'D') ? 12                                                             // Dec
                                : 0;
constexpr unsigned int compileDay = (__DATE__[4] == ' ') ? (__DATE__[5] - '0') : (__DATE__[4] - '0') * 10 + (__DATE__[5] - '0');

constexpr char IsoDate[] =
{   compileYear/1000 + '0', (compileYear % 1000)/100 + '0', (compileYear % 100)/10 + '0', compileYear % 10 + '0',
    '-',  compileMonth/10 + '0', compileMonth%10 + '0',
    '-',  compileDay/10 + '0', compileDay%10 + '0',
    0
};

// Test that it gets it right today
#include <cstring>
static_assert(strcmp(IsoDate, "2020-11-06") == 0);
于 2020-11-06T16:13:50.900 回答
0

如果您需要一种真正跨平台的方式来将编译时间戳字符串格式化为 ISO 8601 或在编译时定义的任何其他格式,您可以考虑使用CMake(考虑使用总是好的)。

使用 CMake 可以轻松实现您想要的。

于 2015-07-14T09:02:30.417 回答
-1

clang 和 gcc 为此使用了 C 函数“asctime”,我想 icc 也使用它。在 Linux 上,您可以使用 LD_PRELOAD 来捕获 asctime 调用并替换为您想要的任何字符串。

于 2013-07-06T01:15:22.640 回答