Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SystemZ][z/OS] Add UtcClock extension to chrono.h/.cpp #67846

Merged
merged 2 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions llvm/include/llvm/Support/Chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,33 @@ 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;
return system_clock::to_time_t(
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) {
Expand All @@ -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<>
///
Expand All @@ -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[] = "";
Expand Down
45 changes: 40 additions & 5 deletions llvm/lib/Support/Chrono.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")];
Expand All @@ -50,12 +68,10 @@ 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 &LT, 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";
std::string Format;
Expand Down Expand Up @@ -90,4 +106,23 @@ void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS,
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
1 change: 1 addition & 0 deletions llvm/unittests/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ add_llvm_unittest(SupportTests
TypeTraitsTest.cpp
TrailingObjectsTest.cpp
UnicodeTest.cpp
UTCTimeTest.cpp
VersionTupleTest.cpp
VirtualFileSystemTest.cpp
WithColorTest.cpp
Expand Down
41 changes: 41 additions & 0 deletions llvm/unittests/Support/UTCTimeTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===- 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.
// 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(UTCTime, convertutc) {
// Get the current time.
time_t currentTime;
time(&currentTime);

// 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(&currentTime);
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