string(TIMESTAMP): Add %z and %Z for adding time zone string

Fixes: #24056
This commit is contained in:
Vasiliy Koyrev
2022-10-13 11:55:54 +03:00
committed by Brad King
parent 2954a810ce
commit 9da542d5c1
8 changed files with 105 additions and 7 deletions

View File

@@ -522,6 +522,17 @@ specifiers:
``%Y``
The current year.
``%z``
.. versionadded:: 3.26
The offset of the time zone from UTC, in hours and minutes,
with format ``+hhmm`` or ``-hhmm``.
``%Z``
.. versionadded:: 3.26
The time zone name.
Unknown format specifiers will be ignored and copied to the output
as-is.

View File

@@ -0,0 +1,5 @@
timestamp-timezone
------------------
* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` commands
now support the ``%z`` and ``%Z`` specifiers for the time zone.

View File

@@ -128,8 +128,8 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
: static_cast<char>(0);
if (c1 == '%' && c2 != 0) {
result +=
this->AddTimestampComponent(c2, timeStruct, timeT, microseconds);
result += this->AddTimestampComponent(c2, timeStruct, timeT, utcFlag,
microseconds);
++i;
} else {
result += c1;
@@ -179,7 +179,7 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
}
std::string cmTimestamp::AddTimestampComponent(
char flag, struct tm& timeStruct, const time_t timeT,
char flag, struct tm& timeStruct, const time_t timeT, const bool utcFlag,
const uint32_t microseconds) const
{
std::string formatString = cmStrCat('%', flag);
@@ -203,6 +203,63 @@ std::string cmTimestamp::AddTimestampComponent(
case 'Y':
case '%':
break;
case 'Z':
#if defined(__GLIBC__)
// 'struct tm' has the time zone, so strftime can honor UTC.
static_cast<void>(utcFlag);
#else
// 'struct tm' may not have the time zone, so strftime may
// use local time. Hard-code the UTC result.
if (utcFlag) {
return std::string("GMT");
}
#endif
break;
case 'z': {
#if defined(__GLIBC__)
// 'struct tm' has the time zone, so strftime can honor UTC.
static_cast<void>(utcFlag);
#else
// 'struct tm' may not have the time zone, so strftime may
// use local time. Hard-code the UTC result.
if (utcFlag) {
return std::string("+0000");
}
#endif
#ifndef _AIX
break;
#else
std::string xpg_sus_old;
bool const xpg_sus_was_set =
cmSystemTools::GetEnv("XPG_SUS_ENV", xpg_sus_old);
if (xpg_sus_was_set && xpg_sus_old == "ON") {
break;
}
xpg_sus_old = "XPG_SUS_ENV=" + xpg_sus_old;
// On AIX systems, %z requires XPG_SUS_ENV=ON to work as desired.
cmSystemTools::PutEnv("XPG_SUS_ENV=ON");
tzset();
char buffer[16];
size_t size = strftime(buffer, sizeof(buffer), "%z", &timeStruct);
# ifndef CMAKE_BOOTSTRAP
if (xpg_sus_was_set) {
cmSystemTools::PutEnv(xpg_sus_old);
} else {
cmSystemTools::UnsetEnv("XPG_SUS_ENV");
}
# else
// No UnsetEnv during bootstrap. This is good enough for CMake itself.
cmSystemTools::PutEnv(xpg_sus_old);
static_cast<void>(xpg_sus_was_set);
# endif
tzset();
return std::string(buffer, size);
#endif
}
case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
{
// Build a time_t for UNIX epoch and subtract from the input "timeT":

View File

@@ -32,6 +32,6 @@ private:
time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
std::string AddTimestampComponent(char flag, struct tm& timeStruct,
time_t timeT,
uint32_t microseconds = 0) const;
time_t timeT, bool utcFlag,
uint32_t microseconds) const;
};

View File

@@ -0,0 +1,22 @@
string(TIMESTAMP output "%z")
STRING(LENGTH output output_length)
message("~${output}~")
set(expected_output_length 6)
if(NOT(${output_length} EQUAL ${expected_output_length}))
message(FATAL_ERROR "expected ${expected_output_length} entries in output with all specifiers; found ${output_length}")
endif()
string(SUBSTRING ${output} 0 1 output0)
string(SUBSTRING ${output} 4 1 output4)
if(NOT((${output0} STREQUAL "-") OR (${output0} STREQUAL "+")))
message(FATAL_ERROR "expected output[0] equ '+' or '-'; found: '${output0}'")
endif()
if(NOT((${output4} STREQUAL "0") OR (${output4} STREQUAL "5")))
message(FATAL_ERROR "expected output[4] equ '0' or '5'; found: '${output4}'")
endif()

View File

@@ -44,6 +44,8 @@ set(TIMESTAMP-IncompleteSpecifier-RESULT 0)
set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
set(TIMESTAMP-AllSpecifiers-RESULT 0)
set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
set(TIMESTAMP-TimeZone-RESULT 0)
set(TIMESTAMP-TimeZone-STDERR "~[-,+][0-9][0-9][0-9][0-9]~")
set(TIMESTAMP-MonthWeekNames-RESULT 0)
set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~")
set(TIMESTAMP-UnixTime-RESULT 0)
@@ -75,6 +77,7 @@ check_cmake_test(String
TIMESTAMP-IncompleteSpecifier
TIMESTAMP-AllSpecifiers
TIMESTAMP-MonthWeekNames
TIMESTAMP-TimeZone
TIMESTAMP-UnixTime
)

View File

@@ -1 +1 @@
RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789
^RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789 TZ=GMT tz=\+0000$

View File

@@ -1,3 +1,3 @@
set(ENV{SOURCE_DATE_EPOCH} "1123456789")
string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC)
string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z" UTC)
message("RESULT=${RESULT}")