Как мне заменить __TIMESTAMP__
в ISO 8601:2004?
__TIMESTAMP__
Sat Jul 6 02:50:06 2013
vs
__TIMESTAMP_ISO__
2013-07-06T00:50:06Z
Как мне заменить __TIMESTAMP__
в ISO 8601:2004?
__TIMESTAMP__
Sat Jul 6 02:50:06 2013
vs
__TIMESTAMP_ISO__
2013-07-06T00:50:06Z
О, оптимист! Вы же не ожидаете, что один стандарт будет обращать внимание на другой, не так ли? Как вы знаете, определения __TIMESTAMP__
нет в стандартном C. Было бы здорово иметь такой формат, как предложенный вами __TIMESTAMP_ISO__
(вы всегда хотите зулусское время или было бы лучше иметь смещение местного часового пояса?), но, честно говоря, самый простой способ добавить его - это патч для GCC и Clang и так далее.
Вы можете попробовать поиграть с asctime()
, как это было предложено user1034749 ответ, но я бы не стал этого делать.
В руководстве 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;
}
CFLAGS += -D__TIMESTAMP_ISO__=$(shell date -u +'"\"%Y-%m-%dT%H:%M:%SZ\""')
прекрасно работает с clang, gcc, icc и т. д. :)
- person Cetin Sert; 07.07.2013
-DTIMESTAMP_ISO=...
и быть полностью свободным от риска (столкновения с будущими воплощениями «реализации»).
- person Jonathan Leffler; 07.07.2013
-r $(SRC)
, где SRC
— переменная make для текущего скомпилированного файла, как в CFLAGS += -DTIMESTAMP_ISO=$(shell date -r $(SRC) -u +'"\"%Y-%m-%dT%H:%M:%SZ\""')
, я точно соответствую исходному поведению __TIMESTAMP__
; а именно, дата не меняется при каждой сборке, если исходный файл не был изменен до сборки.
- person Cetin Sert; 08.07.2013
date
и оболочку bash
.
- person Laryx Decidua; 13.03.2014
date
a> и совместимую с POSIX оболочку, которая распознает $(…)
для подстановки команд. Цитирование также зависит от оболочки POSIX. Для среды Windows я бы, вероятно, написал программу на языке C для генерации #define TIMESTAMP_ISO "2014-09-28T12:00:03"
в файле, таком как timestamp.h
, а затем #include "timestamp.h"
в компилируемом коде. Конечно, это также будет работать в POSIX-системах.
- person Jonathan Leffler; 29.09.2014
Ответ @Jonathan Leffler предоставляет отличное решение, но может быть одна вещь, которая была проигнорирована:
Исходный вопрос задавал альтернативный формат __TIMESTAMP__
, в то время как __TIMESTAMP__
должен быть расширен до строки последней измененной даты и времени. текущего исходного файла. Однако первоначальный ответ фактически назначал __TIMESTAMP__
дате-времени запуска gcc (т. е. время сборки), которое работает как __DATE__
и __TIME__
.
Как улучшить:
с помощью @mmond ответ, заменяет команду 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 — это создаваемый исходный код.
Ссылка:
согласно GCC [manual][2]
__TIMESTAMP__
Этот макрос преобразуется в строковую константу, описывающую дату и время последней модификации текущего исходного файла.
Вот способ определить строковую константу, которая содержит дату в отметке времени компиляции. Не составит труда добавить к нему временную часть и заставить работать с __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);
Если вам нужен действительно кросс-платформенный способ форматирования строки отметки времени компиляции в формате ISO 8601 или любом другом формате, определенном во время компиляции, вместо этого вы можете рассмотреть возможность использования CMake (который всегда полезно использовать).
То, что вы хотите, можно легко выполнить с помощью CMake.
clang и gcc использовали для этой цели функцию C "asctime", я полагаю, что icc также использует ее. В Linux вы можете использовать LD_PRELOAD, чтобы поймать вызов asctime и заменить его любой строкой, которую вы хотите.