This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 605589296bba0edc6aa4d26ede7d937c45d8cb3c
Author: Alan M. Carroll <a...@apache.org>
AuthorDate: Fri Jun 8 14:30:53 2018 -0500

    BWF: Add date / time stamp support.
    
    (cherry picked from commit 1a7d10af373f4a86348b42f659b0f42711b95a68)
---
 doc/conf.py                                        |  1 +
 .../internal-libraries/buffer-writer.en.rst        | 29 +++++++++++++++-
 lib/ts/BufferWriterFormat.cc                       | 39 +++++++++++++++++++++-
 lib/ts/bwf_std_format.h                            |  9 +++++
 lib/ts/unit-tests/test_BufferWriterFormat.cc       | 22 ++++++++++++
 5 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/doc/conf.py b/doc/conf.py
index 322769d..2ba2050 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -174,6 +174,7 @@ nitpick_ignore = [ ('cpp:typeOrConcept', 'std')
                  , ('cpp:typeOrConcept', 'std::shared_ptr')
                  , ('cpp:typeOrConcept', 'std::ostream')
                  , ('cpp:typeOrConcept', 'std::string')
+                 , ('cpp:typeOrConcept', 'std::string_view')
                  , ('cpp:typeOrConcept', 'std::tuple')
                  , ('cpp:typeOrConcept', 'V') # template arguments which 
should be matched but aren't.
                  , ('cpp:typeOrConcept', 'Args')
diff --git a/doc/developer-guide/internal-libraries/buffer-writer.en.rst 
b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
index ced90d4..4f7a416 100644
--- a/doc/developer-guide/internal-libraries/buffer-writer.en.rst
+++ b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
@@ -728,6 +728,33 @@ For :code:`errno` this is handy in another way as 
:code:`ts::bwf::Errno` will pr
     // some other code generating diagnostics that might tweak errno.
     w.print("File not open - {}", last_err);
 
+These are the existing format classes in header file ``bfw_std_format.h``. All 
are in the :code:`ts::bwf` namespace.
+
+.. class:: Errno
+
+    Formating for :code:`errno`.
+
+    .. function:: Errno(int errno)
+
+.. class:: Date
+
+    Date formatting in the :code:`strftime` style.
+
+    .. function:: Date(time_t epoch, std::string_view fmt = "%Y %b %d 
%H:%M:%S")
+
+        :arg:`epoch` is the time to print. :arg:`fmt` is the format for 
printing which is identical to that of `strftime 
<https://linux.die.net/man/3/strftime>`__. The default format looks like "2018 
Jun 08 13:55:37".
+
+    .. function:: Date(std::string_view fmt = "%Y %b %d %H:%M:%S")
+
+         As previous except the epoch is the current epoch at the time the 
constructor is invoked. Therefore if the current time is to be printed the 
default constructor can be used.
+
+   When used the format specification can take an extention of "local" which 
formats the time as local time. Otherwise it is GMT.
+   ``w.print("{}", Date("%H:%M"));`` will print the hour and minute as GMT 
values. ``w.print("{::local}", Date("%H:%M"));`` will
+   When used the format specification can take an extention of "local" which 
formats the time as local time. Otherwise it is GMT.
+   ``w.print("{}", Date("%H:%M"));`` will print the hour and minute as GMT 
values. ``w.print("{::local}", Date("%H:%M"));`` will
+   print the hour and minute in the local time zone. ``w.print("{::gmt}"), 
...);`` will output in GMT if additional explicitness is
+   desired.
+
 Global Names
 ++++++++++++
 
@@ -826,7 +853,7 @@ Reference
       Write to the buffer starting at :arg:`data` for at most :arg:`length` 
bytes. If there is not
       enough room to fit all the data, none is written.
 
-   .. function:: BufferWriter & write(string_view str)
+   .. function:: BufferWriter & write(std::string_view str)
 
       Write the string :arg:`str` to the buffer. If there is not enough room 
to write the string no
       data is written.
diff --git a/lib/ts/BufferWriterFormat.cc b/lib/ts/BufferWriterFormat.cc
index 18384c9..e265276 100644
--- a/lib/ts/BufferWriterFormat.cc
+++ b/lib/ts/BufferWriterFormat.cc
@@ -914,6 +914,43 @@ bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno 
const &e)
   return w;
 }
 
+bwf::Date::Date(std::string_view fmt) : 
_epoch(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())), 
_fmt(fmt) {}
+
+BufferWriter &
+bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Date const &date)
+{
+  if (spec.has_numeric_type()) {
+    bwformat(w, spec, date._epoch);
+  } else {
+    struct tm t;
+    auto r = w.remaining();
+    size_t n{0};
+    // Verify @a fmt is null terminated, even outside the bounds of the view.
+    ink_assert(date._fmt.data()[date._fmt.size() - 1] == 0 || 
date._fmt.data()[date._fmt.size()] == 0);
+    // Get the time, GMT or local if specified.
+    if (spec._ext == "local"sv) {
+      localtime_r(&date._epoch, &t);
+    } else {
+      gmtime_r(&date._epoch, &t);
+    }
+    // Try a direct write, faster if it works.
+    if (r > 0) {
+      n = strftime(w.auxBuffer(), r, date._fmt.data(), &t);
+    }
+    if (n > 0) {
+      w.fill(n);
+    } else {
+      // Direct write didn't work. Unfortunately need to write to a temporary 
buffer or the sizing
+      // isn't correct if @a w is clipped because @c strftime returns 0 if the 
buffer isn't large
+      // enough.
+      char buff[256]; // hope for the best - no real way to resize 
appropriately on failure.
+      n = strftime(buff, sizeof(buff), date._fmt.data(), &t);
+      w.write(buff, n);
+    }
+  }
+  return w;
+}
+
 } // namespace ts
 
 namespace
@@ -926,7 +963,7 @@ BWF_Timestamp(ts::BufferWriter &w, ts::BWFSpec const &spec)
   char buff[32];
   std::time_t t = std::time(nullptr);
   auto n        = strftime(buff, sizeof(buff), "%Y %b %d %H:%M:%S", 
std::localtime(&t));
-  w.write(std::string_view{buff, n});
+  w.write(buff, n);
 }
 
 void
diff --git a/lib/ts/bwf_std_format.h b/lib/ts/bwf_std_format.h
index fdc998f..60776c4 100644
--- a/lib/ts/bwf_std_format.h
+++ b/lib/ts/bwf_std_format.h
@@ -24,6 +24,7 @@
 #pragma once
 
 #include <atomic>
+#include <string_view>
 
 namespace std
 {
@@ -43,8 +44,16 @@ namespace bwf
     int _e;
     explicit Errno(int e) : _e(e) {}
   };
+
+  struct Date {
+    time_t _epoch;
+    std::string_view _fmt;
+    Date(time_t t, std::string_view fmt = "%Y %b %d %H:%M:%S"sv) : _epoch(t), 
_fmt(fmt) {}
+    Date(std::string_view fmt = "%Y %b %d %H:%M:%S"sv);
+  };
 } // namespace bwf
 
 BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno const 
&e);
+BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Date const 
&date);
 
 } // namespace ts
diff --git a/lib/ts/unit-tests/test_BufferWriterFormat.cc 
b/lib/ts/unit-tests/test_BufferWriterFormat.cc
index f1f5f3a..cda89e7 100644
--- a/lib/ts/unit-tests/test_BufferWriterFormat.cc
+++ b/lib/ts/unit-tests/test_BufferWriterFormat.cc
@@ -489,6 +489,28 @@ TEST_CASE("bwstring std formats", "[libts][bwprint]")
   REQUIRE(w.view() == "EACCES: Permission denied [13]"sv);
   w.reset().print("{}", ts::bwf::Errno(134));
   REQUIRE(w.view().substr(0, 22) == "Unknown: Unknown error"sv);
+
+  time_t t = 1528484137;
+  // default is GMT
+  w.reset().print("{} is {}", t, ts::bwf::Date(t));
+  REQUIRE(w.view() == "1528484137 is 2018 Jun 08 18:55:37");
+  w.reset().print("{} is {}", t, ts::bwf::Date(t, "%a, %d %b %Y at %H.%M.%S"));
+  REQUIRE(w.view() == "1528484137 is Fri, 08 Jun 2018 at 18.55.37");
+  // OK to be explicit
+  w.reset().print("{} is {::gmt}", t, ts::bwf::Date(t));
+  REQUIRE(w.view() == "1528484137 is 2018 Jun 08 18:55:37");
+  w.reset().print("{} is {::gmt}", t, ts::bwf::Date(t, "%a, %d %b %Y at 
%H.%M.%S"));
+  REQUIRE(w.view() == "1528484137 is Fri, 08 Jun 2018 at 18.55.37");
+  // Local time - set it to something specific or the test will be 
geographically sensitive.
+  setenv("TZ", "CST6", 1);
+  tzset();
+  w.reset().print("{} is {::local}", t, ts::bwf::Date(t));
+  REQUIRE(w.view() == "1528484137 is 2018 Jun 08 12:55:37");
+  w.reset().print("{} is {::local}", t, ts::bwf::Date(t, "%a, %d %b %Y at 
%H.%M.%S"));
+  REQUIRE(w.view() == "1528484137 is Fri, 08 Jun 2018 at 12.55.37");
+
+  // Verify these compile and run, not really much hope to check output.
+  w.reset().print("|{}|   |{}|", ts::bwf::Date(), ts::bwf::Date("%a, %d %b 
%Y"));
 }
 
 // Normally there's no point in running the performance tests, but it's worth 
keeping the code

Reply via email to