Merge topic 'unix-timestamps'
6727270b
CMake: Extend TIMESTAMP sub-commands with new unix time format specifier
This commit is contained in:
commit
c387325d4a
|
@ -277,6 +277,7 @@ specifiers:
|
||||||
%j The day of the current year (001-366).
|
%j The day of the current year (001-366).
|
||||||
%m The month of the current year (01-12).
|
%m The month of the current year (01-12).
|
||||||
%M The minute of the current hour (00-59).
|
%M The minute of the current hour (00-59).
|
||||||
|
%s Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
|
||||||
%S The second of the current minute.
|
%S The second of the current minute.
|
||||||
60 represents a leap second. (00-60)
|
60 represents a leap second. (00-60)
|
||||||
%U The week number of the current year (00-53).
|
%U The week number of the current year (00-53).
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
unix-timestamps
|
||||||
|
---------------
|
||||||
|
|
||||||
|
* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)`
|
||||||
|
commands gained support for the ``%s`` placeholder. This is
|
||||||
|
the number of seconds since the UNIX Epoch.
|
|
@ -12,9 +12,11 @@
|
||||||
#include "cmTimestamp.h"
|
#include "cmTimestamp.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::string cmTimestamp::CurrentTime(
|
std::string cmTimestamp::CurrentTime(
|
||||||
|
@ -44,7 +46,7 @@ std::string cmTimestamp::FileModificationTime(const char* path,
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
|
std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
|
||||||
std::string formatString, bool utcFlag)
|
std::string formatString, bool utcFlag) const
|
||||||
{
|
{
|
||||||
if(formatString.empty())
|
if(formatString.empty())
|
||||||
{
|
{
|
||||||
|
@ -79,12 +81,12 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
|
||||||
for(std::string::size_type i = 0; i < formatString.size(); ++i)
|
for(std::string::size_type i = 0; i < formatString.size(); ++i)
|
||||||
{
|
{
|
||||||
char c1 = formatString[i];
|
char c1 = formatString[i];
|
||||||
char c2 = (i+1 < formatString.size()) ?
|
char c2 = (i + 1 < formatString.size()) ?
|
||||||
formatString[i+1] : static_cast<char>(0);
|
formatString[i + 1] : static_cast<char>(0);
|
||||||
|
|
||||||
if(c1 == '%' && c2 != 0)
|
if(c1 == '%' && c2 != 0)
|
||||||
{
|
{
|
||||||
result += AddTimestampComponent(c2, timeStruct);
|
result += AddTimestampComponent(c2, timeStruct, timeT);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -96,9 +98,41 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
|
||||||
return result;
|
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 = "TZ=";
|
||||||
|
if (const char* tz = cmSystemTools::GetEnv("TZ"))
|
||||||
|
{
|
||||||
|
tz_old += tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(
|
std::string cmTimestamp::AddTimestampComponent(
|
||||||
char flag, struct tm& timeStruct)
|
char flag, struct tm& timeStruct, const time_t timeT) const
|
||||||
{
|
{
|
||||||
std::string formatString = "%";
|
std::string formatString = "%";
|
||||||
formatString += flag;
|
formatString += flag;
|
||||||
|
@ -117,6 +151,26 @@ std::string cmTimestamp::AddTimestampComponent(
|
||||||
case 'y':
|
case 'y':
|
||||||
case 'Y':
|
case 'Y':
|
||||||
break;
|
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 aginst CMake");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << static_cast<long int>(difftime(timeT, unixEpoch));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return formatString;
|
return formatString;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
/** \class cmTimestamp
|
/** \class cmTimestamp
|
||||||
* \brief Utility class to generate sting representation of a timestamp
|
* \brief Utility class to generate string representation of a timestamp
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class cmTimestamp
|
class cmTimestamp
|
||||||
|
@ -30,10 +30,13 @@ public:
|
||||||
const std::string& formatString, bool utcFlag);
|
const std::string& formatString, bool utcFlag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string CreateTimestampFromTimeT(time_t timeT,
|
time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
|
||||||
std::string formatString, bool utcFlag);
|
|
||||||
|
|
||||||
std::string AddTimestampComponent(char flag, struct tm& timeStruct);
|
std::string CreateTimestampFromTimeT(
|
||||||
|
time_t timeT, std::string formatString, bool utcFlag) const;
|
||||||
|
|
||||||
|
std::string AddTimestampComponent(
|
||||||
|
char flag, struct tm& timeStruct, time_t timeT) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
string(TIMESTAMP timestamp "[%Y-%m-%d %H:%M:%S] %s" UTC)
|
||||||
|
|
||||||
|
string(TIMESTAMP unix_time "%s")
|
||||||
|
|
||||||
|
string(TIMESTAMP year "%Y" UTC)
|
||||||
|
string(TIMESTAMP days "%j" UTC)
|
||||||
|
|
||||||
|
# Doing proper date calculations here to verify unix timestamps
|
||||||
|
# could be error prone.
|
||||||
|
# At the very least use some safe lower and upper bounds to
|
||||||
|
# see if we are somewhere in the right region.
|
||||||
|
|
||||||
|
math(EXPR years_since_epoch "${year} - 1970")
|
||||||
|
math(EXPR lower_bound "((${years_since_epoch} * 365) + ${days}) * 86400")
|
||||||
|
math(EXPR upper_bound "((${years_since_epoch} * 366) + ${days}) * 86400")
|
||||||
|
|
||||||
|
|
||||||
|
if(unix_time GREATER lower_bound AND unix_time LESS upper_bound)
|
||||||
|
message("~${unix_time}~")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "${timestamp} unix time not in expected range [${lower_bound}, ${upper_bound}]")
|
||||||
|
endif()
|
|
@ -36,6 +36,8 @@ set(TIMESTAMP-IncompleteSpecifier-RESULT 0)
|
||||||
set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
|
set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
|
||||||
set(TIMESTAMP-AllSpecifiers-RESULT 0)
|
set(TIMESTAMP-AllSpecifiers-RESULT 0)
|
||||||
set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
|
set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
|
||||||
|
set(TIMESTAMP-UnixTime-RESULT 0)
|
||||||
|
set(TIMESTAMP-UnixTime-STDERR "~[1-9][0-9]+~")
|
||||||
|
|
||||||
include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
|
include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
|
||||||
check_cmake_test(String
|
check_cmake_test(String
|
||||||
|
@ -58,6 +60,7 @@ check_cmake_test(String
|
||||||
TIMESTAMP-UnknownSpecifier
|
TIMESTAMP-UnknownSpecifier
|
||||||
TIMESTAMP-IncompleteSpecifier
|
TIMESTAMP-IncompleteSpecifier
|
||||||
TIMESTAMP-AllSpecifiers
|
TIMESTAMP-AllSpecifiers
|
||||||
|
TIMESTAMP-UnixTime
|
||||||
)
|
)
|
||||||
|
|
||||||
# Execute each test listed in StringTestScript.cmake:
|
# Execute each test listed in StringTestScript.cmake:
|
||||||
|
@ -68,9 +71,12 @@ set(number_of_tests_expected 70)
|
||||||
include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
|
include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
|
||||||
execute_all_script_tests(${scriptname} number_of_tests_executed)
|
execute_all_script_tests(${scriptname} number_of_tests_executed)
|
||||||
|
|
||||||
|
string(TIMESTAMP timestamp "[%Y-%m-%d %H:%M:%S] UTC %s" UTC)
|
||||||
|
|
||||||
# And verify that number_of_tests_executed is at least as many as we know
|
# And verify that number_of_tests_executed is at least as many as we know
|
||||||
# about as of this writing...
|
# about as of this writing...
|
||||||
#
|
#
|
||||||
|
message(STATUS "timestamp='${timestamp}'")
|
||||||
message(STATUS "scriptname='${scriptname}'")
|
message(STATUS "scriptname='${scriptname}'")
|
||||||
message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
|
message(STATUS "number_of_tests_executed='${number_of_tests_executed}'")
|
||||||
message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
|
message(STATUS "number_of_tests_expected='${number_of_tests_expected}'")
|
||||||
|
|
Loading…
Reference in New Issue