From 304b4e97bef93bcbeb82b5339451bacbb72b4f31 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Jan 2016 23:18:05 +0200 Subject: Fix nanoseconds formatting in to_stream(), operator<<() --- butl/timestamp | 4 ++++ butl/timestamp.cxx | 50 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/butl/timestamp b/butl/timestamp index e68a59f..aaef04d 100644 --- a/butl/timestamp +++ b/butl/timestamp @@ -61,6 +61,10 @@ namespace butl // // Note also that these operators/function may throw std::system_error. // + // Finally, padding is not fully supported by these operators/function. They + // throw runtime_error if nanoseconds conversion specifier is present and + // the stream's width field has been set to non-zero value before the call. + // // Potential improvements: // - add flag to to_stream() to use // - support %[U] (microseconds) and %[M] (milliseconds). diff --git a/butl/timestamp.cxx b/butl/timestamp.cxx index 8c53f60..6b99284 100644 --- a/butl/timestamp.cxx +++ b/butl/timestamp.cxx @@ -8,9 +8,10 @@ #include // EINVAL #include // tm, strftime() -#include // put_time() +#include // put_time(), setw(), dec, right #include // strlen(), memcpy() #include +#include // runtime_error #include using namespace std; @@ -101,6 +102,10 @@ namespace butl { if (fmt[j + 1] == '[') { + if (os.width () != 0) + throw runtime_error ( + "padding is not supported when printing nanoseconds"); + // Our fragment. First see if we need to call put_time(). // if (i != j) @@ -129,9 +134,12 @@ namespace butl { if (d != '\0') os << d; - os.width (9); - os.fill ('0'); - os << ns.count (); + + ostream::fmtflags fl (os.flags ()); + char fc (os.fill ('0')); + os << dec << right << setw (9) << ns.count (); + os.fill (fc); + os.flags (fl); } i = j + 1; // j is incremented in the for-loop header. @@ -155,6 +163,10 @@ namespace butl ostream& operator<< (ostream& os, const duration& d) { + if (os.width () != 0) // We always print nanosecond. + throw runtime_error ( + "padding is not supported when printing nanoseconds"); + timestamp ts; // Epoch. ts += d; @@ -162,17 +174,17 @@ namespace butl const char* fmt (nullptr); const char* unt ("nanoseconds"); - if (t >= 365 * 12 * 24 * 60 * 60) + if (t >= 365 * 24 * 60 * 60) { fmt = "%Y-%m-%d %H:%M:%S"; unt = "years"; } - else if (t >= 12 * 24 * 60* 60) + else if (t >= 31 * 24 * 60 * 60) { fmt = "%m-%d %H:%M:%S"; unt = "months"; } - else if (t >= 24 * 60* 60) + else if (t >= 24 * 60 * 60) { fmt = "%d %H:%M:%S"; unt = "days"; @@ -199,6 +211,18 @@ namespace butl if (gmtime_r (&t, &tm) == nullptr) throw system_error (errno, system_category ()); + if (t >= 24 * 60 * 60) + tm.tm_mday -= 1; // Make day of the month to be a zero-based number. + + if (t >= 31 * 24 * 60 * 60) + tm.tm_mon -= 1; // Make month of the year to be a zero-based number. + + if (t >= 365 * 24 * 60 * 60) + // Make the year to be a 1970-based number. Negative values allowed + // according to the POSIX specification. + // + tm.tm_year -= 1970; + if (!(os << put_time (&tm, fmt))) return os; } @@ -212,12 +236,16 @@ namespace butl { if (fmt != nullptr) { - os << '.'; - os.width (9); - os.fill ('0'); + ostream::fmtflags fl (os.flags ()); + char fc (os.fill ('0')); + os << '.' << dec << right << setw (9) << ns.count (); + os.fill (fc); + os.flags (fl); } + else + os << ns.count (); - os << ns.count () << ' ' << unt; + os << ' ' << unt; } else if (fmt == nullptr) os << '0'; -- cgit v1.1