cmTimestamp.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. if (!cmsys::SystemTools::FileExists(path)) {
  32. return std::string();
  33. }
  34. time_t mtime = cmsys::SystemTools::ModifiedTime(path);
  35. return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
  36. }
  37. std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
  38. std::string formatString,
  39. bool utcFlag) const
  40. {
  41. if (formatString.empty()) {
  42. formatString = "%Y-%m-%dT%H:%M:%S";
  43. if (utcFlag) {
  44. formatString += "Z";
  45. }
  46. }
  47. struct tm timeStruct;
  48. memset(&timeStruct, 0, sizeof(timeStruct));
  49. struct tm* ptr = nullptr;
  50. if (utcFlag) {
  51. ptr = gmtime(&timeT);
  52. } else {
  53. ptr = localtime(&timeT);
  54. }
  55. if (ptr == nullptr) {
  56. return std::string();
  57. }
  58. timeStruct = *ptr;
  59. std::string result;
  60. for (std::string::size_type i = 0; i < formatString.size(); ++i) {
  61. char c1 = formatString[i];
  62. char c2 = (i + 1 < formatString.size()) ? formatString[i + 1]
  63. : static_cast<char>(0);
  64. if (c1 == '%' && c2 != 0) {
  65. result += AddTimestampComponent(c2, timeStruct, timeT);
  66. ++i;
  67. } else {
  68. result += c1;
  69. }
  70. }
  71. return result;
  72. }
  73. time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
  74. {
  75. #if defined(_MSC_VER) && _MSC_VER >= 1400
  76. return _mkgmtime(&tm);
  77. #else
  78. // From Linux timegm() manpage.
  79. std::string tz_old;
  80. cmSystemTools::GetEnv("TZ", tz_old);
  81. tz_old = "TZ=" + tz_old;
  82. // The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC.
  83. // It seems that "TZ=" does NOT work, at least under Windows
  84. // with neither MSVC nor MinGW, so let's use explicit "TZ=UTC"
  85. cmSystemTools::PutEnv("TZ=UTC");
  86. tzset();
  87. time_t result = mktime(&tm);
  88. cmSystemTools::PutEnv(tz_old);
  89. tzset();
  90. return result;
  91. #endif
  92. }
  93. std::string cmTimestamp::AddTimestampComponent(char flag,
  94. struct tm& timeStruct,
  95. const time_t timeT) const
  96. {
  97. std::string formatString = "%";
  98. formatString += flag;
  99. switch (flag) {
  100. case 'a':
  101. case 'A':
  102. case 'b':
  103. case 'B':
  104. case 'd':
  105. case 'H':
  106. case 'I':
  107. case 'j':
  108. case 'm':
  109. case 'M':
  110. case 'S':
  111. case 'U':
  112. case 'w':
  113. case 'y':
  114. case 'Y':
  115. case '%':
  116. break;
  117. case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
  118. {
  119. // Build a time_t for UNIX epoch and substract from the input "timeT":
  120. struct tm tmUnixEpoch;
  121. memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch));
  122. tmUnixEpoch.tm_mday = 1;
  123. tmUnixEpoch.tm_year = 1970 - 1900;
  124. const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch);
  125. if (unixEpoch == -1) {
  126. cmSystemTools::Error(
  127. "Error generating UNIX epoch in "
  128. "STRING(TIMESTAMP ...). Please, file a bug report aginst CMake");
  129. return std::string();
  130. }
  131. std::ostringstream ss;
  132. ss << static_cast<long int>(difftime(timeT, unixEpoch));
  133. return ss.str();
  134. }
  135. default: {
  136. return formatString;
  137. }
  138. }
  139. char buffer[16];
  140. size_t size =
  141. strftime(buffer, sizeof(buffer), formatString.c_str(), &timeStruct);
  142. return std::string(buffer, size);
  143. }