[llvm] [SystemZ][z/OS] Add UtcClock extension to chrono.h/.cpp (PR #67846)
Yusra Syeda via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 11 11:47:07 PDT 2023
https://github.com/ysyeda updated https://github.com/llvm/llvm-project/pull/67846
>From 637472dc67b62524b5b4cdc4687c9cea3578f39f Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Fri, 29 Sep 2023 15:45:27 -0400
Subject: [PATCH 1/2] utc time extension to chrono
---
llvm/include/llvm/Support/Chrono.h | 26 ++++++++
llvm/lib/Support/Chrono.cpp | 91 ++++++++++++++++++--------
llvm/unittests/Support/CMakeLists.txt | 1 +
llvm/unittests/Support/UTFTimeTest.cpp | 42 ++++++++++++
4 files changed, 133 insertions(+), 27 deletions(-)
create mode 100644 llvm/unittests/Support/UTFTimeTest.cpp
diff --git a/llvm/include/llvm/Support/Chrono.h b/llvm/include/llvm/Support/Chrono.h
index 9c2bd45d2803e56..71859af7c7e4a59 100644
--- a/llvm/include/llvm/Support/Chrono.h
+++ b/llvm/include/llvm/Support/Chrono.h
@@ -33,6 +33,19 @@ namespace sys {
template <typename D = std::chrono::nanoseconds>
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
+// utc_clock and utc_time are only available since C++20. Add enough code to
+// support formatting date/time in UTC.
+class UtcClock : public std::chrono::system_clock {};
+
+template <typename D = std::chrono::nanoseconds>
+using UtcTime = std::chrono::time_point<UtcClock, D>;
+
+/// Convert a std::time_t to a UtcTime
+inline UtcTime<std::chrono::seconds> toUtcTime(std::time_t T) {
+ using namespace std::chrono;
+ return UtcTime<seconds>(seconds(T));
+}
+
/// Convert a TimePoint to std::time_t
inline std::time_t toTimeT(TimePoint<> TP) {
using namespace std::chrono;
@@ -40,6 +53,13 @@ inline std::time_t toTimeT(TimePoint<> TP) {
time_point_cast<system_clock::time_point::duration>(TP));
}
+/// Convert a UtcTime to std::time_t
+inline std::time_t toTimeT(UtcTime<> TP) {
+ using namespace std::chrono;
+ return system_clock::to_time_t(time_point<system_clock, seconds>(
+ duration_cast<seconds>(TP.time_since_epoch())));
+}
+
/// Convert a std::time_t to a TimePoint
inline TimePoint<std::chrono::seconds>
toTimePoint(std::time_t T) {
@@ -58,6 +78,7 @@ toTimePoint(std::time_t T, uint32_t nsec) {
} // namespace sys
raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
+raw_ostream &operator<<(raw_ostream &OS, sys::UtcTime<> TP);
/// Format provider for TimePoint<>
///
@@ -73,6 +94,11 @@ struct format_provider<sys::TimePoint<>> {
StringRef Style);
};
+template <> struct format_provider<sys::UtcTime<std::chrono::seconds>> {
+ static void format(const sys::UtcTime<std::chrono::seconds> &TP,
+ llvm::raw_ostream &OS, StringRef Style);
+};
+
namespace detail {
template <typename Period> struct unit { static const char value[]; };
template <typename Period> const char unit<Period>::value[] = "";
diff --git a/llvm/lib/Support/Chrono.cpp b/llvm/lib/Support/Chrono.cpp
index 859ece8f550080c..4e64f03eea224e6 100644
--- a/llvm/lib/Support/Chrono.cpp
+++ b/llvm/lib/Support/Chrono.cpp
@@ -40,6 +40,24 @@ static inline struct tm getStructTM(TimePoint<> TP) {
return Storage;
}
+static inline struct tm getStructTMUtc(UtcTime<> TP) {
+ struct tm Storage;
+ std::time_t OurTime = toTimeT(TP);
+
+#if defined(LLVM_ON_UNIX)
+ struct tm *LT = ::gmtime_r(&OurTime, &Storage);
+ assert(LT);
+ (void)LT;
+#endif
+#if defined(_WIN32)
+ int Error = ::gmtime_s(&Storage, &OurTime);
+ assert(!Error);
+ (void)Error;
+#endif
+
+ return Storage;
+}
+
raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) {
struct tm LT = getStructTM(TP);
char Buffer[sizeof("YYYY-MM-DD HH:MM:SS")];
@@ -50,44 +68,63 @@ raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) {
.count()));
}
-void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS,
- StringRef Style) {
+template <class T>
+static void format(const T &Fractional, struct tm <, raw_ostream &OS,
+ StringRef Style) {
using namespace std::chrono;
- TimePoint<seconds> Truncated = time_point_cast<seconds>(T);
- auto Fractional = T - Truncated;
- struct tm LT = getStructTM(Truncated);
// Handle extensions first. strftime mangles unknown %x on some platforms.
- if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N";
+ if (Style.empty())
+ Style = "%Y-%m-%d %H:%M:%S.%N";
std::string Format;
raw_string_ostream FStream(Format);
for (unsigned I = 0; I < Style.size(); ++I) {
- if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) {
- case 'L': // Milliseconds, from Ruby.
- FStream << llvm::format(
- "%.3lu", (long)duration_cast<milliseconds>(Fractional).count());
- ++I;
- continue;
- case 'f': // Microseconds, from Python.
- FStream << llvm::format(
- "%.6lu", (long)duration_cast<microseconds>(Fractional).count());
- ++I;
- continue;
- case 'N': // Nanoseconds, from date(1).
- FStream << llvm::format(
- "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count());
- ++I;
- continue;
- case '%': // Consume %%, so %%f parses as (%%)f not %(%f)
- FStream << "%%";
- ++I;
- continue;
+ if (Style[I] == '%' && Style.size() > I + 1)
+ switch (Style[I + 1]) {
+ case 'L': // Milliseconds, from Ruby.
+ FStream << llvm::format(
+ "%.3lu", (long)duration_cast<milliseconds>(Fractional).count());
+ ++I;
+ continue;
+ case 'f': // Microseconds, from Python.
+ FStream << llvm::format(
+ "%.6lu", (long)duration_cast<microseconds>(Fractional).count());
+ ++I;
+ continue;
+ case 'N': // Nanoseconds, from date(1).
+ FStream << llvm::format(
+ "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count());
+ ++I;
+ continue;
+ case '%': // Consume %%, so %%f parses as (%%)f not %(%f)
+ FStream << "%%";
+ ++I;
+ continue;
}
FStream << Style[I];
}
FStream.flush();
- char Buffer[256]; // Should be enough for anywhen.
+ char Buffer[256]; // Should be enough for anywhen.
size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), <);
OS << (Len ? Buffer : "BAD-DATE-FORMAT");
}
+void format_provider<UtcTime<std::chrono::seconds>>::format(
+ const UtcTime<std::chrono::seconds> &T, raw_ostream &OS, StringRef Style) {
+ using namespace std::chrono;
+ UtcTime<seconds> Truncated =
+ UtcTime<seconds>(duration_cast<seconds>(T.time_since_epoch()));
+ auto Fractional = T - Truncated;
+ struct tm LT = getStructTMUtc(Truncated);
+ llvm::format(Fractional, LT, OS, Style);
+}
+
+void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS,
+ StringRef Style) {
+ using namespace std::chrono;
+ TimePoint<seconds> Truncated = time_point_cast<seconds>(T);
+ auto Fractional = T - Truncated;
+ struct tm LT = getStructTM(Truncated);
+ llvm::format(Fractional, LT, OS, Style);
+}
+
} // namespace llvm
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 12f2e9959326045..064a31effaeb0fa 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -90,6 +90,7 @@ add_llvm_unittest(SupportTests
TypeTraitsTest.cpp
TrailingObjectsTest.cpp
UnicodeTest.cpp
+ UTFTimeTest.cpp
VersionTupleTest.cpp
VirtualFileSystemTest.cpp
WithColorTest.cpp
diff --git a/llvm/unittests/Support/UTFTimeTest.cpp b/llvm/unittests/Support/UTFTimeTest.cpp
new file mode 100644
index 000000000000000..de69bd0313455b2
--- /dev/null
+++ b/llvm/unittests/Support/UTFTimeTest.cpp
@@ -0,0 +1,42 @@
+//===- unittests/Support/UTFTestTest.cpp ----------------- ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Chrono.h"
+#include "gtest/gtest.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace llvm {
+namespace sys {
+namespace {
+
+TEST(UTFTime, convertutc) {
+ // Get the current time.
+ time_t currentTime;
+ time(¤tTime);
+
+ // Convert with toUtcTime.
+ SmallString<15> customResultString;
+ raw_svector_ostream T(customResultString);
+ T << formatv("{0:%Y-%m-%d %H:%M:%S}", llvm::sys::toUtcTime(currentTime));
+
+
+ // Convert with gmtime.
+ char gmtimeResultString[20];
+ std::tm *gmtimeResult = std::gmtime(¤tTime);
+ assert(gmtimeResult != NULL);
+ std::strftime(gmtimeResultString, 20, "%Y-%m-%d %H:%M:%S", gmtimeResult);
+
+ // Compare the formatted strings.
+ EXPECT_EQ(customResultString, StringRef(gmtimeResultString, 19));
+
+}
+} // namespace
+} // namespace sys
+} // namespace llvm
>From 799f3e01ffecf79de6082efc7a768684a587b94b Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Wed, 11 Oct 2023 14:46:41 -0400
Subject: [PATCH 2/2] fix formatting + typo
---
llvm/lib/Support/Chrono.cpp | 46 +++++++++----------
llvm/unittests/Support/CMakeLists.txt | 2 +-
.../{UTFTimeTest.cpp => UTCTimeTest.cpp} | 5 +-
3 files changed, 25 insertions(+), 28 deletions(-)
rename llvm/unittests/Support/{UTFTimeTest.cpp => UTCTimeTest.cpp} (92%)
diff --git a/llvm/lib/Support/Chrono.cpp b/llvm/lib/Support/Chrono.cpp
index 4e64f03eea224e6..993d200675fe572 100644
--- a/llvm/lib/Support/Chrono.cpp
+++ b/llvm/lib/Support/Chrono.cpp
@@ -73,37 +73,35 @@ static void format(const T &Fractional, struct tm <, raw_ostream &OS,
StringRef Style) {
using namespace std::chrono;
// Handle extensions first. strftime mangles unknown %x on some platforms.
- if (Style.empty())
- Style = "%Y-%m-%d %H:%M:%S.%N";
+ if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N";
std::string Format;
raw_string_ostream FStream(Format);
for (unsigned I = 0; I < Style.size(); ++I) {
- if (Style[I] == '%' && Style.size() > I + 1)
- switch (Style[I + 1]) {
- case 'L': // Milliseconds, from Ruby.
- FStream << llvm::format(
- "%.3lu", (long)duration_cast<milliseconds>(Fractional).count());
- ++I;
- continue;
- case 'f': // Microseconds, from Python.
- FStream << llvm::format(
- "%.6lu", (long)duration_cast<microseconds>(Fractional).count());
- ++I;
- continue;
- case 'N': // Nanoseconds, from date(1).
- FStream << llvm::format(
- "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count());
- ++I;
- continue;
- case '%': // Consume %%, so %%f parses as (%%)f not %(%f)
- FStream << "%%";
- ++I;
- continue;
+ if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) {
+ case 'L': // Milliseconds, from Ruby.
+ FStream << llvm::format(
+ "%.3lu", (long)duration_cast<milliseconds>(Fractional).count());
+ ++I;
+ continue;
+ case 'f': // Microseconds, from Python.
+ FStream << llvm::format(
+ "%.6lu", (long)duration_cast<microseconds>(Fractional).count());
+ ++I;
+ continue;
+ case 'N': // Nanoseconds, from date(1).
+ FStream << llvm::format(
+ "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count());
+ ++I;
+ continue;
+ case '%': // Consume %%, so %%f parses as (%%)f not %(%f)
+ FStream << "%%";
+ ++I;
+ continue;
}
FStream << Style[I];
}
FStream.flush();
- char Buffer[256]; // Should be enough for anywhen.
+ char Buffer[256]; // Should be enough for anywhen.
size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), <);
OS << (Len ? Buffer : "BAD-DATE-FORMAT");
}
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 064a31effaeb0fa..5baece87d3ee101 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -90,7 +90,7 @@ add_llvm_unittest(SupportTests
TypeTraitsTest.cpp
TrailingObjectsTest.cpp
UnicodeTest.cpp
- UTFTimeTest.cpp
+ UTCTimeTest.cpp
VersionTupleTest.cpp
VirtualFileSystemTest.cpp
WithColorTest.cpp
diff --git a/llvm/unittests/Support/UTFTimeTest.cpp b/llvm/unittests/Support/UTCTimeTest.cpp
similarity index 92%
rename from llvm/unittests/Support/UTFTimeTest.cpp
rename to llvm/unittests/Support/UTCTimeTest.cpp
index de69bd0313455b2..64e04d29376c3af 100644
--- a/llvm/unittests/Support/UTFTimeTest.cpp
+++ b/llvm/unittests/Support/UTCTimeTest.cpp
@@ -1,4 +1,4 @@
-//===- unittests/Support/UTFTestTest.cpp ----------------- ----------------===//
+//===- unittests/Support/UTCTimeTest.cpp ----------------- ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -16,7 +16,7 @@ namespace llvm {
namespace sys {
namespace {
-TEST(UTFTime, convertutc) {
+TEST(UTCTime, convertutc) {
// Get the current time.
time_t currentTime;
time(¤tTime);
@@ -26,7 +26,6 @@ TEST(UTFTime, convertutc) {
raw_svector_ostream T(customResultString);
T << formatv("{0:%Y-%m-%d %H:%M:%S}", llvm::sys::toUtcTime(currentTime));
-
// Convert with gmtime.
char gmtimeResultString[20];
std::tm *gmtimeResult = std::gmtime(¤tTime);
More information about the llvm-commits
mailing list