From aafa392c12f6fe04893bc5327af429f5321fbb9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Antons=20Je=C4=BCkins?= <Antons.Jelkins@bmw.de>
Date: Wed, 21 Jul 2021 15:52:45 +0200
Subject: string(TIMESTAMP): Add %V specifier for ISO 8601 week number

In ISO 8601 weeks begin with Monday. The first week of
the year is the week which contains the first Thursday
of the year.
---
 Help/command/string.rst                           |  5 +++++
 Help/release/dev/string-TIMESTAMP-specifier-V.rst |  5 +++++
 Source/cmTimestamp.cxx                            | 23 +++++++++++++++++++++++
 Tests/RunCMake/string/Timestamp-stderr.txt        |  2 +-
 Tests/RunCMake/string/Timestamp.cmake             |  2 +-
 5 files changed, 35 insertions(+), 2 deletions(-)
 create mode 100644 Help/release/dev/string-TIMESTAMP-specifier-V.rst

diff --git a/Help/command/string.rst b/Help/command/string.rst
index 6fac0e6..29ad082 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -493,6 +493,11 @@ specifiers:
 ``%U``
   The week number of the current year (00-53).
 
+``%V``
+  .. versionadded:: 3.22
+
+  The ISO 8601 week number of the current year (01-53).
+
 ``%w``
   The day of the current week. 0 is Sunday. (0-6)
 
diff --git a/Help/release/dev/string-TIMESTAMP-specifier-V.rst b/Help/release/dev/string-TIMESTAMP-specifier-V.rst
new file mode 100644
index 0000000..afd3f03
--- /dev/null
+++ b/Help/release/dev/string-TIMESTAMP-specifier-V.rst
@@ -0,0 +1,5 @@
+string-TIMESTAMP-specifier-V
+----------------------------
+
+* The :command:`string(TIMESTAMP)` command now supports the ``%V``
+  specifier for ISO 8601 week numbers.
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 056696d..cfea4cf 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -18,6 +18,10 @@
 #include <cstring>
 #include <sstream>
 
+#ifdef __MINGW32__
+#  include <libloaderapi.h>
+#endif
+
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -159,6 +163,7 @@ std::string cmTimestamp::AddTimestampComponent(char flag,
     case 'M':
     case 'S':
     case 'U':
+    case 'V':
     case 'w':
     case 'y':
     case 'Y':
@@ -187,6 +192,24 @@ std::string cmTimestamp::AddTimestampComponent(char flag,
     }
   }
 
+#ifdef __MINGW32__
+  /* See a bug in MinGW: https://sourceforge.net/p/mingw-w64/bugs/793/. A work
+   * around is to try to use strftime() from ucrtbase.dll. */
+  using T = size_t(WINAPI*)(char*, size_t, const char*, const struct tm*);
+  auto loadStrftime = [] {
+    auto handle =
+      LoadLibraryExA("ucrtbase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+    if (handle) {
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wcast-function-type"
+      return reinterpret_cast<T>(GetProcAddress(handle, "strftime"));
+#  pragma GCC diagnostic pop
+    }
+    return strftime;
+  };
+  static T strftime = loadStrftime();
+#endif
+
   char buffer[16];
 
   size_t size =
diff --git a/Tests/RunCMake/string/Timestamp-stderr.txt b/Tests/RunCMake/string/Timestamp-stderr.txt
index cd4dcb3..d54777b 100644
--- a/Tests/RunCMake/string/Timestamp-stderr.txt
+++ b/Tests/RunCMake/string/Timestamp-stderr.txt
@@ -1 +1 @@
-RESULT=2005-08-07 23:19:49 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 %I=11 epoch=1123456789
+RESULT=2005-08-07 23:19:49 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789
diff --git a/Tests/RunCMake/string/Timestamp.cmake b/Tests/RunCMake/string/Timestamp.cmake
index cba258d..7fd6d72 100644
--- a/Tests/RunCMake/string/Timestamp.cmake
+++ b/Tests/RunCMake/string/Timestamp.cmake
@@ -1,3 +1,3 @@
 set(ENV{SOURCE_DATE_EPOCH} "1123456789")
-string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S %A=%a %B=%b %y day=%j wd=%w week=%U %%I=%I epoch=%s" UTC)
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC)
 message("RESULT=${RESULT}")
-- 
cgit v0.12