llvm.org GIT mirror llvm / ebd014b
Support formatv of TimePoint with strftime-style formats. Summary: Support formatv of TimePoint with strftime-style formats. Extensions for millis/micros/nanos are added. Inital use case is HH:MM:SS.MMM timestamps in clangd logs. Reviewers: bkramer, ilya-biryukov Subscribers: labath, llvm-commits Differential Revision: https://reviews.llvm.org/D38992 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316419 91177308-0d34-0410-b5e6-96231b3b80d8 Sam McCall 1 year, 9 months ago
3 changed file(s) with 80 addition(s) and 24 deletion(s). Raw diff Collapse all Expand all
4949 } // namespace sys
5050
5151 raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
52
53 /// Format provider for TimePoint<>
54 ///
55 /// The options string is a strftime format string, with extensions:
56 /// - %L is millis: 000-999
57 /// - %f is micros: 000000-999999
58 /// - %N is nanos: 000000000 - 999999999
59 ///
60 /// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
61 template <>
62 struct format_provider> {
63 static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
64 StringRef Style);
65 };
5266
5367 /// Implementation of format_provider for duration types.
5468 ///
5050 .count()));
5151 }
5252
53 void format_provider>::format(const TimePoint<> &T, raw_ostream &OS,
54 StringRef Style) {
55 using namespace std::chrono;
56 TimePoint Truncated = time_point_cast(T);
57 auto Fractional = T - Truncated;
58 struct tm LT = getStructTM(Truncated);
59 // Handle extensions first. strftime mangles unknown %x on some platforms.
60 if (Style.empty()) Style = "%Y-%m-%d %H:%M:%S.%N";
61 std::string Format;
62 raw_string_ostream FStream(Format);
63 for (unsigned I = 0; I < Style.size(); ++I) {
64 if (Style[I] == '%' && Style.size() > I + 1) switch (Style[I + 1]) {
65 case 'L': // Milliseconds, from Ruby.
66 FStream << llvm::format(
67 "%.3lu", duration_cast(Fractional).count());
68 ++I;
69 continue;
70 case 'f': // Microseconds, from Python.
71 FStream << llvm::format(
72 "%.6lu", duration_cast(Fractional).count());
73 ++I;
74 continue;
75 case 'N': // Nanoseconds, from date(1).
76 FStream << llvm::format(
77 "%.6lu", duration_cast(Fractional).count());
78 ++I;
79 continue;
80 case '%': // Consume %%, so %%f parses as (%%)f not %(%f)
81 FStream << "%%";
82 ++I;
83 continue;
84 }
85 FStream << Style[I];
86 }
87 FStream.flush();
88 char Buffer[256]; // Should be enough for anywhen.
89 size_t Len = strftime(Buffer, sizeof(Buffer), Format.c_str(), <);
90 OS << (Len ? Buffer : "BAD-DATE-FORMAT");
91 }
92
5393 } // namespace llvm
3030 EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
3131 }
3232
33 TEST(Chrono, StringConversion) {
33 TEST(Chrono, TimePointFormat) {
34 using namespace std::chrono;
35 struct tm TM {};
36 TM.tm_year = 106;
37 TM.tm_mon = 0;
38 TM.tm_mday = 2;
39 TM.tm_hour = 15;
40 TM.tm_min = 4;
41 TM.tm_sec = 5;
42 TM.tm_isdst = -1;
43 TimePoint<> T =
44 system_clock::from_time_t(mktime(&TM)) + nanoseconds(123456789);
45
46 // operator<< uses the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN
3447 std::string S;
3548 raw_string_ostream OS(S);
36 OS << system_clock::now();
49 OS << T;
50 EXPECT_EQ("2006-01-02 15:04:05.123456789", OS.str());
3751
38 // Do a basic sanity check on the output.
39 // The format we expect is YYYY-MM-DD HH:MM:SS.MMMUUUNNN
40 StringRef Date, Time;
41 std::tie(Date, Time) = StringRef(OS.str()).split(' ');
42
43 SmallVector Components;
44 Date.split(Components, '-');
45 ASSERT_EQ(3u, Components.size());
46 EXPECT_EQ(4u, Components[0].size());
47 EXPECT_EQ(2u, Components[1].size());
48 EXPECT_EQ(2u, Components[2].size());
49
50 StringRef Sec, Nano;
51 std::tie(Sec, Nano) = Time.split('.');
52
53 Components.clear();
54 Sec.split(Components, ':');
55 ASSERT_EQ(3u, Components.size());
56 EXPECT_EQ(2u, Components[0].size());
57 EXPECT_EQ(2u, Components[1].size());
58 EXPECT_EQ(2u, Components[2].size());
59 EXPECT_EQ(9u, Nano.size());
52 // formatv default style matches operator<<.
53 EXPECT_EQ("2006-01-02 15:04:05.123456789", formatv("{0}", T).str());
54 // formatv supports strftime-style format strings.
55 EXPECT_EQ("15:04:05", formatv("{0:%H:%M:%S}", T).str());
56 // formatv supports our strftime extensions for sub-second precision.
57 EXPECT_EQ("123", formatv("{0:%L}", T).str());
58 EXPECT_EQ("123456", formatv("{0:%f}", T).str());
59 EXPECT_EQ("123456789", formatv("{0:%N}", T).str());
60 // our extensions don't interfere with %% escaping.
61 EXPECT_EQ("%foo", formatv("{0:%%foo}", T).str());
6062 }
6163
6264 // Test that toTimePoint and toTimeT can be called with a arguments with varying