diff --git a/Help/command/string.rst b/Help/command/string.rst
index 77538f64c7dbd1cdd8e8263b39c974106f907176..2c7847acc3793157cc31530d4792309b27cab17e 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -329,6 +329,12 @@ If no explicit ``<format string>`` is given it will default to:
 
 Write a string which can be used as an identifier in C.
 
+.. note::
+
+  If the ``SOURCE_DATE_EPOCH`` environment variable is set,
+  its value will be used instead of the current time.
+  See https://reproducible-builds.org/specs/source-date-epoch/ for details.
+
 UUID
 """"
 
diff --git a/Help/release/dev/SOURCE_DATE_EPOCH.rst b/Help/release/dev/SOURCE_DATE_EPOCH.rst
new file mode 100644
index 0000000000000000000000000000000000000000..576e1da257a927aa2589a5ff2d936d841da2a44a
--- /dev/null
+++ b/Help/release/dev/SOURCE_DATE_EPOCH.rst
@@ -0,0 +1,5 @@
+SOURCE_DATE_EPOCH
+-----------------
+
+* The :command:`string(TIMESTAMP)` will now honor the ``SOURCE_DATE_EPOCH``
+  environment variable and use its value instead of the current time.
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 4a971149840ad70c2e0baaa1a0f3d8498c888c01..1e5ac5b2d0969290ea43de03626e9fbc3ed6b398 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -5,6 +5,7 @@
 #include <cmConfigure.h>
 #include <cstring>
 #include <sstream>
+#include <stdlib.h>
 
 #include "cmSystemTools.h"
 
@@ -12,6 +13,16 @@ std::string cmTimestamp::CurrentTime(const std::string& formatString,
                                      bool utcFlag)
 {
   time_t currentTimeT = time(CM_NULLPTR);
+  std::string source_date_epoch;
+  cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
+  if (!source_date_epoch.empty()) {
+    std::istringstream iss(source_date_epoch);
+    iss >> currentTimeT;
+    if (iss.fail() || !iss.eof()) {
+      cmSystemTools::Error("Cannot parse SOURCE_DATE_EPOCH as integer");
+      exit(27);
+    }
+  }
   if (currentTimeT == time_t(-1)) {
     return std::string();
   }
diff --git a/Tests/RunCMake/string/RunCMakeTest.cmake b/Tests/RunCMake/string/RunCMakeTest.cmake
index 8067d9dbf4dff5123f712a83f241ccb83f62762d..38a77b0d1c283968646147c4ac7eb9586f48a263 100644
--- a/Tests/RunCMake/string/RunCMakeTest.cmake
+++ b/Tests/RunCMake/string/RunCMakeTest.cmake
@@ -6,6 +6,11 @@ run_cmake(AppendNoArgs)
 run_cmake(Concat)
 run_cmake(ConcatNoArgs)
 
+run_cmake(Timestamp)
+run_cmake(TimestampEmpty)
+run_cmake(TimestampInvalid)
+run_cmake(TimestampInvalid2)
+
 run_cmake(Uuid)
 run_cmake(UuidMissingNamespace)
 run_cmake(UuidMissingNamespaceValue)
diff --git a/Tests/RunCMake/string/Timestamp-result.txt b/Tests/RunCMake/string/Timestamp-result.txt
new file mode 100644
index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56
--- /dev/null
+++ b/Tests/RunCMake/string/Timestamp-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/string/Timestamp-stderr.txt b/Tests/RunCMake/string/Timestamp-stderr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c12b0707e66536b3415f37a724f3cc4a0bf0d040
--- /dev/null
+++ b/Tests/RunCMake/string/Timestamp-stderr.txt
@@ -0,0 +1 @@
+RESULT=2005-08-07 23:19:49 Sun Aug 05 day=219 wd=0 week=32 %%I=11
diff --git a/Tests/RunCMake/string/Timestamp.cmake b/Tests/RunCMake/string/Timestamp.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..1232300156bc2b6e8b84598ee98f13627a947dc7
--- /dev/null
+++ b/Tests/RunCMake/string/Timestamp.cmake
@@ -0,0 +1,3 @@
+set(ENV{SOURCE_DATE_EPOCH} "1123456789")
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S %a %b %y day=%j wd=%w week=%U %%I=%I" UTC)
+message("RESULT=${RESULT}")
diff --git a/Tests/RunCMake/string/TimestampEmpty-result.txt b/Tests/RunCMake/string/TimestampEmpty-result.txt
new file mode 100644
index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampEmpty-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/string/TimestampEmpty-stderr.txt b/Tests/RunCMake/string/TimestampEmpty-stderr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..35cbd3ceb4c9f4585f1ab0ec4815a28116361542
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampEmpty-stderr.txt
@@ -0,0 +1 @@
+RESULT=2
diff --git a/Tests/RunCMake/string/TimestampEmpty.cmake b/Tests/RunCMake/string/TimestampEmpty.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..21b770fd6c01b89bd286e03992b8f2d357bbc2ba
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampEmpty.cmake
@@ -0,0 +1,3 @@
+set(ENV{SOURCE_DATE_EPOCH} "")
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S" UTC)
+message("RESULT=${RESULT}")
diff --git a/Tests/RunCMake/string/TimestampInvalid-result.txt b/Tests/RunCMake/string/TimestampInvalid-result.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f64f5d8d85ac0230d36724bd7e6ba351a95b4942
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid-result.txt
@@ -0,0 +1 @@
+27
diff --git a/Tests/RunCMake/string/TimestampInvalid-stderr.txt b/Tests/RunCMake/string/TimestampInvalid-stderr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..75566da00ede5391a8dce4502ef8f01e63e885d2
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid-stderr.txt
@@ -0,0 +1 @@
+CMake Error: Cannot parse SOURCE_DATE_EPOCH as integer
diff --git a/Tests/RunCMake/string/TimestampInvalid.cmake b/Tests/RunCMake/string/TimestampInvalid.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ab362708aae137273c6e6a635c45b3c6f4d60654
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid.cmake
@@ -0,0 +1,3 @@
+set(ENV{SOURCE_DATE_EPOCH} "invalid-integer")
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S" UTC)
+message("RESULT=${RESULT}")
diff --git a/Tests/RunCMake/string/TimestampInvalid2-result.txt b/Tests/RunCMake/string/TimestampInvalid2-result.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f64f5d8d85ac0230d36724bd7e6ba351a95b4942
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid2-result.txt
@@ -0,0 +1 @@
+27
diff --git a/Tests/RunCMake/string/TimestampInvalid2-stderr.txt b/Tests/RunCMake/string/TimestampInvalid2-stderr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..75566da00ede5391a8dce4502ef8f01e63e885d2
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid2-stderr.txt
@@ -0,0 +1 @@
+CMake Error: Cannot parse SOURCE_DATE_EPOCH as integer
diff --git a/Tests/RunCMake/string/TimestampInvalid2.cmake b/Tests/RunCMake/string/TimestampInvalid2.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..5cc61b8b149969763acabc9fa471067f07bba488
--- /dev/null
+++ b/Tests/RunCMake/string/TimestampInvalid2.cmake
@@ -0,0 +1,3 @@
+set(ENV{SOURCE_DATE_EPOCH} "123trailing-garbage")
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S" UTC)
+message("RESULT=${RESULT}")