ISO 8601:2004中的C预处理器时间戳

ISO 8601:2004中的C预处理器时间戳,c,gcc,clang,c-preprocessor,icc,C,Gcc,Clang,C Preprocessor,Icc,如何在ISO 8601:2004中替换时间戳 \uuuu时间戳 Sat Jul 6 02:50:06 2013 vs \uuuu时间戳\uu ISO\uuuuu 2013-07-06T00:50:06Z clang和gcc为此使用了C函数“asctime”,我想icc也使用了它。在Linux上,您可以使用LD_PRELOAD捕获asctime调用并替换为您想要的任何字符串。哦,是的,乐观主义者!你不会真的期望一个标准关注另一个标准吧?正如您所知,\uuuuuu时间戳\uuuuuu定义不在标

如何在ISO 8601:2004中替换时间戳

\uuuu时间戳

Sat Jul  6 02:50:06 2013
vs

\uuuu时间戳\uu ISO\uuuuu

2013-07-06T00:50:06Z

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

哦,是的,乐观主义者!你不会真的期望一个标准关注另一个标准吧?正如您所知,
\uuuuuu时间戳\uuuuuu
定义不在标准C中。如果有一个像您建议的
\uuuuu TIMESTAMP\uiso\uuuuuu
这样的格式就太好了(您总是想要祖鲁时间,还是最好有本地时区偏移量?),但坦率地说,添加它的最简单方法可能是对GCC和Clang进行修补,等等

您可以按照的建议尝试使用
asctime()
蒙骗,但我不想尝试

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

-重新定义Wno内置宏

如果某些内置宏被重新定义,则不要发出警告。这将禁止重新定义
\uuuuuuuuu时间戳
\uuuu时间
\uuuu日期
\uuuu文件
,以及
\uuuu基本文件\uuuuu

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);
这建议您可以尝试:

gcc ... -Wno-builtin-macro-redefined -D__TIMESTAMP__=$(date +'"%Y-%m-%dT%H:%M:%S"') ...
(注意从
date
中获取字符串所需的象形文字,并用双引号括起来。)但是,一些早期版本的GCC不支持该选项;我不记得以前见过它。您仍然可以重新定义时间戳:

$ 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
$
$gcc-std=c99-Wall-Wextra-O xx.c-O xx
美元/xx
2013年7月5日星期五19:56:25
$gcc-std=c99-Wall-Wextra-D_uuu时间戳uuu=$(日期+'%Y-%m-%dT%H:%m:%S“)-O xx.c-O xx
:警告:“\uuuu时间戳\uuuuu”已重新定义
美元/xx
2013-07-05T20:10:28
$
不是很漂亮,但是很管用。。。哦,为了记录在案,源代码是(微不足道的):

#包括
内部主(空)
{
printf(“%s\n”,时间戳);
返回0;
}

< /代码> 如果您需要一个真正的跨平台的方式来编译ISO 8601中的编译时戳字符串或编译时定义的任何其他格式,您可以考虑使用(总是很好地考虑使用)。
你想要什么。

@Jonathan Leffler的答案提供了一个极好的解决方案,但可能有一件事被忽略了:
最初的问题是询问
\uuuuuuuuuuuu
的替代格式,而
\uuuuuuuuu
将扩展为当前源文件最后一次修改的日期时间字符串。 然而,最初的答案实际上是将运行gcc的日期时间分配给
\uuuuuuu TIMESTAMP\uuuuu
(即buildingtime),它作为
\uuuuuuu日期
\uuu时间
工作

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);
如何改进
使用@mmond's,将
-D\u TIMESTAMP\u=…
中的
date+'%Y-%m-%dT%H:%m:%s'
命令替换为
date+'%Y-%m-%dT%H:%s'-r xx.c
,即在运行
date
命令时将选项
-r xx.c
添加到引用xx.c。c是正在构建的源代码

参考资料:
根据GCC的
[手册][2]

\uuuu时间戳

此宏扩展为一个字符串常量,用于描述上次修改当前源文件的日期和时间


下面是一种定义字符串常量的方法,该常量保存编译时戳的日期部分。将时间部分添加到它中,并使它从
\uuuuu TIMESTAMP\uuuuuuu
而不是
\uuuu DATE\uuuuuuu
工作并不困难

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);
constexpr unsigned int compileYear=(\uuuu-DATE\uuuuu7]-'0')*1000+(\uuuu-DATE\uuu8]-'0')*100+(\uuuuu-DATE\uuuu9]-'0')*10+(\uuuu-DATE\uu8]-'0');
constexpr unsigned int compileMonth=(\uuuu DATE\uuuu[0]=='J')?(日期)1:(日期)6:7)//一月,六月或七月
:(\uuuu日期\uuuuu[0]=“F”)?二月二日
:(\uuuu日期\uuuuu[0]=“M”)?(日期:3:5)//3月或5月
:(\uuuu日期\uuuuu[0]=“A”)?((日期)(2)(p))(4:8)//4月或8月
:(\uuuu日期\uuuuu[0]=='S')?9月9日
:(\uuuu日期\uuuuu[0]=“O”)?10月10日
:(\uuuu日期\uuuuu[0]=“N”)?11月11日
:(\uuuu日期\uuuu[0]=“D”)?12//12月
: 0;
constexpr unsigned int compileDay=(\uuuuu DATE\uuuuu[4]=“”)?(“日期”[5]-“0”):(“日期”[4]-“0”)*10+(“日期”[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”,
“-”,编译日期/10+“0”,编译日期%10+“0”,
0
};
//测试它今天是否正确
#包括
静态断言(strcmp(IsoDate,“2020-11-06”)==0);

非常感谢!我在我的makefile中使用了这个:
CFLAGS+=-D\uu TIMESTAMP\u ISO\uuu=$(shell日期-u+'“\%Y-%m-%dT%H:%m:%SZ\”)
与clang、gcc、icc等配合使用效果很好:)很高兴它能起作用-它应该起作用。理论上,您不应该使用以双下划线开头的名称;它们是为“实现”保留的。正如我所指出的,您不太可能真正遇到问题,但您也可以使用
-DTIMESTAMP\u ISO=…
,完全避免风险(与“实现”的未来版本冲突):)我将更新我的美国