|
|
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
|
|
#include "cmTimestamp.h"
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "cmSystemTools.h"
|
|
|
|
|
|
|
|
std::string cmTimestamp::CurrentTime(const std::string& formatString,
|
|
|
|
bool utcFlag)
|
|
|
|
{
|
|
|
|
time_t currentTimeT = time(nullptr);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (currentTimeT == time_t(-1)) {
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string cmTimestamp::FileModificationTime(const char* path,
|
|
|
|
const std::string& formatString,
|
|
|
|
bool utcFlag)
|
|
|
|
{
|
|
|
|
std::string real_path =
|
|
|
|
cmSystemTools::GetRealPathResolvingWindowsSubst(path);
|
|
|
|
|
|
|
|
if (!cmsys::SystemTools::FileExists(real_path)) {
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t mtime = cmsys::SystemTools::ModifiedTime(real_path);
|
|
|
|
return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
|
|
|
|
std::string formatString,
|
|
|
|
bool utcFlag) const
|
|
|
|
{
|
|
|
|
if (formatString.empty()) {
|
|
|
|
formatString = "%Y-%m-%dT%H:%M:%S";
|
|
|
|
if (utcFlag) {
|
|
|
|
formatString += "Z";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tm timeStruct;
|
|
|
|
memset(&timeStruct, 0, sizeof(timeStruct));
|
|
|
|
|
|
|
|
struct tm* ptr = nullptr;
|
|
|
|
if (utcFlag) {
|
|
|
|
ptr = gmtime(&timeT);
|
|
|
|
} else {
|
|
|
|
ptr = localtime(&timeT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr == nullptr) {
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
timeStruct = *ptr;
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
for (std::string::size_type i = 0; i < formatString.size(); ++i) {
|
|
|
|
char c1 = formatString[i];
|
|
|
|
char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
|
|
|
|
: static_cast<char>(0);
|
|
|
|
|
|
|
|
if (c1 == '%' && c2 != 0) {
|
|
|
|
result += AddTimestampComponent(c2, timeStruct, timeT);
|
|
|
|
++i;
|
|
|
|
} else {
|
|
|
|
result += c1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
|
|
|
|
{
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
|
|
|
return _mkgmtime(&tm);
|
|
|
|
#else
|
|
|
|
// From Linux timegm() manpage.
|
|
|
|
|
|
|
|
std::string tz_old;
|
|
|
|
cmSystemTools::GetEnv("TZ", tz_old);
|
|
|
|
tz_old = "TZ=" + tz_old;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
{
|
|
|
|
std::string formatString = "%";
|
|
|
|
formatString += flag;
|
|
|
|
|
|
|
|
switch (flag) {
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
case 'b':
|
|
|
|
case 'B':
|
|
|
|
case 'd':
|
|
|
|
case 'H':
|
|
|
|
case 'I':
|
|
|
|
case 'j':
|
|
|
|
case 'm':
|
|
|
|
case 'M':
|
|
|
|
case 'S':
|
|
|
|
case 'U':
|
|
|
|
case 'w':
|
|
|
|
case 'y':
|
|
|
|
case 'Y':
|
|
|
|
case '%':
|
|
|
|
break;
|
|
|
|
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 against CMake");
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << static_cast<long int>(difftime(timeT, unixEpoch));
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
return formatString;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char buffer[16];
|
|
|
|
|
|
|
|
size_t size =
|
|
|
|
strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
|
|
|
|
|
|
|
|
return std::string(buffer, size);
|
|
|
|
}
|