ISO 8601:2004中的C预处理器__TIMESTAMP__

时间:2013-07-06 00:53:53

标签: c gcc clang c-preprocessor icc

如何在ISO 8601:2004中替换__TIMESTAMP__

__TIMESTAMP__

Sat Jul  6 02:50:06 2013

VS

__TIMESTAMP_ISO__

2013-07-06T00:50:06Z

5 个答案:

答案 0 :(得分:17)

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

您可以按照user1034749 answer的建议,尝试使用asctime()进行代理,但我不想尝试。

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

  

-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;
}

答案 1 :(得分:1)

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

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

参考:
根据海湾合作委员会的[manual][2]

  

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

答案 2 :(得分: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);

答案 3 :(得分:0)

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

你想要什么can be easily accomplished with CMake

答案 4 :(得分:-1)

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