cmake/Source/cmTimestamp.cxx

173 lines
4.3 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2013-03-16 19:13:01 +02:00
#include "cmTimestamp.h"
2017-07-20 19:35:53 +02:00
#include "cmConfigure.h"
2013-03-16 19:13:01 +02:00
#include <cstring>
2016-07-09 11:21:54 +02:00
#include <sstream>
2017-04-14 19:02:05 +02:00
#include <stdlib.h>
2013-03-16 19:13:01 +02:00
2017-04-14 19:02:05 +02:00
#include "cmSystemTools.h"
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
std::string cmTimestamp::CurrentTime(const std::string& formatString,
bool utcFlag)
2013-03-16 19:13:01 +02:00
{
2016-10-30 18:24:19 +01:00
time_t currentTimeT = time(CM_NULLPTR);
2017-04-14 19:02:05 +02:00
std::string source_date_epoch;
cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
if (!source_date_epoch.empty()) {
std::istringstream iss(source_date_epoch);
iss >> currentTimeT;
if (iss.fail() || !iss.eof()) {
cmSystemTools::Error("Cannot parse SOURCE_DATE_EPOCH as integer");
exit(27);
}
}
2016-07-09 11:21:54 +02:00
if (currentTimeT == time_t(-1)) {
2013-03-16 19:13:01 +02:00
return std::string();
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
}
std::string cmTimestamp::FileModificationTime(const char* path,
2016-07-09 11:21:54 +02:00
const std::string& formatString,
bool utcFlag)
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
if (!cmsys::SystemTools::FileExists(path)) {
2013-03-16 19:13:01 +02:00
return std::string();
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2015-04-27 22:25:09 +02:00
time_t mtime = cmsys::SystemTools::ModifiedTime(path);
return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
2013-03-16 19:13:01 +02:00
}
std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
2016-07-09 11:21:54 +02:00
std::string formatString,
bool utcFlag) const
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
if (formatString.empty()) {
2013-03-16 19:13:01 +02:00
formatString = "%Y-%m-%dT%H:%M:%S";
2016-07-09 11:21:54 +02:00
if (utcFlag) {
2013-03-16 19:13:01 +02:00
formatString += "Z";
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
struct tm timeStruct;
memset(&timeStruct, 0, sizeof(timeStruct));
2016-10-30 18:24:19 +01:00
struct tm* ptr = (struct tm*)CM_NULLPTR;
2016-07-09 11:21:54 +02:00
if (utcFlag) {
2013-03-16 19:13:01 +02:00
ptr = gmtime(&timeT);
2016-07-09 11:21:54 +02:00
} else {
2013-03-16 19:13:01 +02:00
ptr = localtime(&timeT);
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-10-30 18:24:19 +01:00
if (ptr == CM_NULLPTR) {
2013-03-16 19:13:01 +02:00
return std::string();
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
timeStruct = *ptr;
std::string result;
2016-07-09 11:21:54 +02:00
for (std::string::size_type i = 0; i < formatString.size(); ++i) {
2013-03-16 19:13:01 +02:00
char c1 = formatString[i];
2016-07-09 11:21:54 +02:00
char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
: static_cast<char>(0);
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
if (c1 == '%' && c2 != 0) {
result += AddTimestampComponent(c2, timeStruct, timeT);
2013-03-16 19:13:01 +02:00
++i;
2016-07-09 11:21:54 +02:00
} else {
2013-03-16 19:13:01 +02:00
result += c1;
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
return result;
}
2016-07-09 11:21:54 +02:00
time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
return _mkgmtime(&tm);
#else
// From Linux timegm() manpage.
2017-04-14 19:02:05 +02:00
std::string tz_old;
2016-10-30 18:24:19 +01:00
cmSystemTools::GetEnv("TZ", tz_old);
tz_old = "TZ=" + tz_old;
2016-07-09 11:21:54 +02:00
// The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC.
// It seems that "TZ=" does NOT work, at least under Windows
// with neither MSVC nor MinGW, so let's use explicit "TZ=UTC"
cmSystemTools::PutEnv("TZ=UTC");
tzset();
time_t result = mktime(&tm);
cmSystemTools::PutEnv(tz_old);
tzset();
return result;
#endif
}
std::string cmTimestamp::AddTimestampComponent(char flag,
struct tm& timeStruct,
const time_t timeT) const
2013-03-16 19:13:01 +02:00
{
std::string formatString = "%";
formatString += flag;
2016-07-09 11:21:54 +02:00
switch (flag) {
2016-10-30 18:24:19 +01:00
case 'a':
case 'b':
2013-03-16 19:13:01 +02:00
case 'd':
case 'H':
case 'I':
case 'j':
case 'm':
case 'M':
case 'S':
case 'U':
case 'w':
case 'y':
case 'Y':
2017-04-14 19:02:05 +02:00
case '%':
2013-03-16 19:13:01 +02:00
break;
2016-07-09 11:21:54 +02:00
case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
{
// Build a time_t for UNIX epoch and substract from the input "timeT":
struct tm tmUnixEpoch;
memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch));
tmUnixEpoch.tm_mday = 1;
tmUnixEpoch.tm_year = 1970 - 1900;
const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch);
if (unixEpoch == -1) {
cmSystemTools::Error(
"Error generating UNIX epoch in "
"STRING(TIMESTAMP ...). Please, file a bug report aginst CMake");
return std::string();
2013-03-16 19:13:01 +02:00
}
2016-07-09 11:21:54 +02:00
2016-10-30 18:24:19 +01:00
std::ostringstream ss;
2016-07-09 11:21:54 +02:00
ss << static_cast<long int>(difftime(timeT, unixEpoch));
return ss.str();
}
default: {
return formatString;
2013-03-16 19:13:01 +02:00
}
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
char buffer[16];
2016-07-09 11:21:54 +02:00
size_t size =
strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
2013-03-16 19:13:01 +02:00
return std::string(buffer, size);
}