cmTimestamp.cxx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmTimestamp.h"
  4. #include <cstring>
  5. #include <sstream>
  6. #include <stdlib.h>
  7. #include "cmSystemTools.h"
  8. std::string cmTimestamp::CurrentTime(const std::string& formatString,
  9. bool utcFlag)
  10. {
  11. time_t currentTimeT = time(nullptr);
  12. std::string source_date_epoch;
  13. cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
  14. if (!source_date_epoch.empty()) {
  15. std::istringstream iss(source_date_epoch);
  16. iss >> currentTimeT;
  17. if (iss.fail() || !iss.eof()) {
  18. cmSystemTools::Error("Cannot parse SOURCE_DATE_EPOCH as integer");
  19. exit(27);
  20. }
  21. }
  22. if (currentTimeT == time_t(-1)) {
  23. return std::string();
  24. }
  25. return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
  26. }
  27. std::string cmTimestamp::FileModificationTime(const char* path,
  28. const std::string& formatString,
  29. bool utcFlag)
  30. {
  31. std::string real_path = cmSystemTools::GetRealPath(path);
  32. if (!cmsys::SystemTools::FileExists(real_path)) {
  33. return std::string();
  34. }
  35. time_t mtime = cmsys::SystemTools::ModifiedTime(real_path);
  36. return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
  37. }
  38. std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
  39. std::string formatString,
  40. bool utcFlag) const
  41. {
  42. if (formatString.empty()) {
  43. formatString = "%Y-%m-%dT%H:%M:%S";
  44. if (utcFlag) {
  45. formatString += "Z";
  46. }
  47. }
  48. struct tm timeStruct;
  49. memset(&timeStruct, 0, sizeof(timeStruct));
  50. struct tm* ptr = nullptr;
  51. if (utcFlag) {
  52. ptr = gmtime(&timeT);
  53. } else {
  54. ptr = localtime(&timeT);
  55. }
  56. if (ptr == nullptr) {
  57. return std::string();
  58. }
  59. timeStruct = *ptr;
  60. std::string result;
  61. for (std::string::size_type i = 0; i < formatString.size(); ++i) {
  62. char c1 = formatString[i];
  63. char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
  64. : static_cast<char>(0);
  65. if (c1 == '%' && c2 != 0) {
  66. result += AddTimestampComponent(c2, timeStruct, timeT);
  67. ++i;
  68. } else {
  69. result += c1;
  70. }
  71. }
  72. return result;
  73. }
  74. time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
  75. {
  76. #if defined(_MSC_VER) && _MSC_VER >= 1400
  77. return _mkgmtime(&tm);
  78. #else
  79. // From Linux timegm() manpage.
  80. std::string tz_old;
  81. cmSystemTools::GetEnv("TZ", tz_old);
  82. tz_old = "TZ=" + tz_old;
  83. // The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC.
  84. // It seems that "TZ=" does NOT work, at least under Windows
  85. // with neither MSVC nor MinGW, so let's use explicit "TZ=UTC"
  86. cmSystemTools::PutEnv("TZ=UTC");
  87. tzset();
  88. time_t result = mktime(&tm);
  89. cmSystemTools::PutEnv(tz_old);
  90. tzset();
  91. return result;
  92. #endif
  93. }
  94. std::string cmTimestamp::AddTimestampComponent(char flag,
  95. struct tm& timeStruct,
  96. const time_t timeT) const
  97. {
  98. std::string formatString = "%";
  99. formatString += flag;
  100. switch (flag) {
  101. case 'a':
  102. case 'A':
  103. case 'b':
  104. case 'B':
  105. case 'd':
  106. case 'H':
  107. case 'I':
  108. case 'j':
  109. case 'm':
  110. case 'M':
  111. case 'S':
  112. case 'U':
  113. case 'w':
  114. case 'y':
  115. case 'Y':
  116. case '%':
  117. break;
  118. case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
  119. {
  120. // Build a time_t for UNIX epoch and substract from the input "timeT":
  121. struct tm tmUnixEpoch;
  122. memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch));
  123. tmUnixEpoch.tm_mday = 1;
  124. tmUnixEpoch.tm_year = 1970 - 1900;
  125. const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch);
  126. if (unixEpoch == -1) {
  127. cmSystemTools::Error(
  128. "Error generating UNIX epoch in "
  129. "STRING(TIMESTAMP ...). Please, file a bug report against CMake");
  130. return std::string();
  131. }
  132. std::ostringstream ss;
  133. ss << static_cast<long int>(difftime(timeT, unixEpoch));
  134. return ss.str();
  135. }
  136. default: {
  137. return formatString;
  138. }
  139. }
  140. char buffer[16];
  141. size_t size =
  142. strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
  143. return std::string(buffer, size);
  144. }