Skip to content

Commit

Permalink
[SystemZ][z/OS] Add UtcClock extension to chrono.h/.cpp (llvm#67846)
Browse files Browse the repository at this point in the history
This PR adds handling for UtcClock to chrono.h/.cpp.

---------

Co-authored-by: Yusra Syeda <[email protected]>
  • Loading branch information
ysyeda and Yusra Syeda authored Oct 12, 2023
1 parent 50ece4c commit 1c9035d
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 5 deletions.
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 @@ -91,6 +91,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

0 comments on commit 1c9035d

Please sign in to comment.