10b57cec5SDimitry Andric //===- Support/Chrono.cpp - Utilities for Timing Manipulation ---*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/Support/Chrono.h" 100b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 110b57cec5SDimitry Andric #include "llvm/Support/Format.h" 120b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric namespace llvm { 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace sys; 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<3600>>::value[] = "h"; 190b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<60>>::value[] = "m"; 200b57cec5SDimitry Andric const char llvm::detail::unit<std::ratio<1>>::value[] = "s"; 210b57cec5SDimitry Andric const char llvm::detail::unit<std::milli>::value[] = "ms"; 220b57cec5SDimitry Andric const char llvm::detail::unit<std::micro>::value[] = "us"; 230b57cec5SDimitry Andric const char llvm::detail::unit<std::nano>::value[] = "ns"; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric static inline struct tm getStructTM(TimePoint<> TP) { 260b57cec5SDimitry Andric struct tm Storage; 270b57cec5SDimitry Andric std::time_t OurTime = toTimeT(TP); 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #if defined(LLVM_ON_UNIX) 300b57cec5SDimitry Andric struct tm *LT = ::localtime_r(&OurTime, &Storage); 310b57cec5SDimitry Andric assert(LT); 320b57cec5SDimitry Andric (void)LT; 330b57cec5SDimitry Andric #endif 340b57cec5SDimitry Andric #if defined(_WIN32) 350b57cec5SDimitry Andric int Error = ::localtime_s(&Storage, &OurTime); 360b57cec5SDimitry Andric assert(!Error); 370b57cec5SDimitry Andric (void)Error; 380b57cec5SDimitry Andric #endif 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric return Storage; 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric 43*5f757f3fSDimitry Andric static inline struct tm getStructTMUtc(UtcTime<> TP) { 44*5f757f3fSDimitry Andric struct tm Storage; 45*5f757f3fSDimitry Andric std::time_t OurTime = toTimeT(TP); 46*5f757f3fSDimitry Andric 47*5f757f3fSDimitry Andric #if defined(LLVM_ON_UNIX) 48*5f757f3fSDimitry Andric struct tm *LT = ::gmtime_r(&OurTime, &Storage); 49*5f757f3fSDimitry Andric assert(LT); 50*5f757f3fSDimitry Andric (void)LT; 51*5f757f3fSDimitry Andric #endif 52*5f757f3fSDimitry Andric #if defined(_WIN32) 53*5f757f3fSDimitry Andric int Error = ::gmtime_s(&Storage, &OurTime); 54*5f757f3fSDimitry Andric assert(!Error); 55*5f757f3fSDimitry Andric (void)Error; 56*5f757f3fSDimitry Andric #endif 57*5f757f3fSDimitry Andric 58*5f757f3fSDimitry Andric return Storage; 59*5f757f3fSDimitry Andric } 60*5f757f3fSDimitry Andric 610b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, TimePoint<> TP) { 620b57cec5SDimitry Andric struct tm LT = getStructTM(TP); 630b57cec5SDimitry Andric char Buffer[sizeof("YYYY-MM-DD HH:MM:SS")]; 640b57cec5SDimitry Andric strftime(Buffer, sizeof(Buffer), "%Y-%m-%d %H:%M:%S", <); 650b57cec5SDimitry Andric return OS << Buffer << '.' 660b57cec5SDimitry Andric << format("%.9lu", 670b57cec5SDimitry Andric long((TP.time_since_epoch() % std::chrono::seconds(1)) 680b57cec5SDimitry Andric .count())); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 71*5f757f3fSDimitry Andric template <class T> 72*5f757f3fSDimitry Andric static void format(const T &Fractional, struct tm <, raw_ostream &OS, 730b57cec5SDimitry Andric StringRef Style) { 740b57cec5SDimitry Andric using namespace std::chrono; 750b57cec5SDimitry Andric // Handle extensions first. strftime mangles unknown %x on some platforms. 760b57cec5SDimitry Andric if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N"; 770b57cec5SDimitry Andric std::string Format; 780b57cec5SDimitry Andric raw_string_ostream FStream(Format); 790b57cec5SDimitry Andric for (unsigned I = 0; I < Style.size(); ++I) { 800b57cec5SDimitry Andric if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) { 810b57cec5SDimitry Andric case 'L': // Milliseconds, from Ruby. 820b57cec5SDimitry Andric FStream << llvm::format( 830b57cec5SDimitry Andric "%.3lu", (long)duration_cast<milliseconds>(Fractional).count()); 840b57cec5SDimitry Andric ++I; 850b57cec5SDimitry Andric continue; 860b57cec5SDimitry Andric case 'f': // Microseconds, from Python. 870b57cec5SDimitry Andric FStream << llvm::format( 880b57cec5SDimitry Andric "%.6lu", (long)duration_cast<microseconds>(Fractional).count()); 890b57cec5SDimitry Andric ++I; 900b57cec5SDimitry Andric continue; 910b57cec5SDimitry Andric case 'N': // Nanoseconds, from date(1). 920b57cec5SDimitry Andric FStream << llvm::format( 9306c3fb27SDimitry Andric "%.9lu", (long)duration_cast<nanoseconds>(Fractional).count()); 940b57cec5SDimitry Andric ++I; 950b57cec5SDimitry Andric continue; 960b57cec5SDimitry Andric case '%': // Consume %%, so %%f parses as (%%)f not %(%f) 970b57cec5SDimitry Andric FStream << "%%"; 980b57cec5SDimitry Andric ++I; 990b57cec5SDimitry Andric continue; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric FStream << Style[I]; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric FStream.flush(); 1040b57cec5SDimitry Andric char Buffer[256]; // Should be enough for anywhen. 1050b57cec5SDimitry Andric size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), <); 1060b57cec5SDimitry Andric OS << (Len ? Buffer : "BAD-DATE-FORMAT"); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 109*5f757f3fSDimitry Andric void format_provider<UtcTime<std::chrono::seconds>>::format( 110*5f757f3fSDimitry Andric const UtcTime<std::chrono::seconds> &T, raw_ostream &OS, StringRef Style) { 111*5f757f3fSDimitry Andric using namespace std::chrono; 112*5f757f3fSDimitry Andric UtcTime<seconds> Truncated = 113*5f757f3fSDimitry Andric UtcTime<seconds>(duration_cast<seconds>(T.time_since_epoch())); 114*5f757f3fSDimitry Andric auto Fractional = T - Truncated; 115*5f757f3fSDimitry Andric struct tm LT = getStructTMUtc(Truncated); 116*5f757f3fSDimitry Andric llvm::format(Fractional, LT, OS, Style); 117*5f757f3fSDimitry Andric } 118*5f757f3fSDimitry Andric 119*5f757f3fSDimitry Andric void format_provider<TimePoint<>>::format(const TimePoint<> &T, raw_ostream &OS, 120*5f757f3fSDimitry Andric StringRef Style) { 121*5f757f3fSDimitry Andric using namespace std::chrono; 122*5f757f3fSDimitry Andric TimePoint<seconds> Truncated = time_point_cast<seconds>(T); 123*5f757f3fSDimitry Andric auto Fractional = T - Truncated; 124*5f757f3fSDimitry Andric struct tm LT = getStructTM(Truncated); 125*5f757f3fSDimitry Andric llvm::format(Fractional, LT, OS, Style); 126*5f757f3fSDimitry Andric } 127*5f757f3fSDimitry Andric 1280b57cec5SDimitry Andric } // namespace llvm 129