]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/ceph_time: move operator<<(ostream&, timespan&) into std namespace
authorKefu Chai <kchai@redhat.com>
Thu, 7 Jan 2021 07:17:45 +0000 (15:17 +0800)
committerDavid Galloway <dgallowa@redhat.com>
Wed, 11 May 2022 16:26:00 +0000 (12:26 -0400)
otherwise compiler is not able to find it as the "timespan" here is
actually a class defined in std namespace, even it has an alias defined
in ceph namespace like:

typedef std::chrono::duration<rep, std::nano> timespan;

but this does not make it a member of "ceph" namespace. for more details
on the lookup rules, see https://en.cppreference.com/w/cpp/language/adl

Signed-off-by: Kefu Chai <kchai@redhat.com>
(cherry picked from commit 75aafcba888a5753d2a4a8378637b4bb9fad5dd0)

src/common/ceph_time.cc
src/common/ceph_time.h

index bb708bb4675646d467ff0fe4ab5033997c63901f..9b85fc88224d3edb807176b0f21c1e2255127a8d 100644 (file)
 
 // For ceph_timespec
 #include "ceph_time.h"
+
+#include <fmt/chrono.h>
+#include <fmt/ostream.h>
+
 #include "log/LogClock.h"
 #include "config.h"
 #include "strtol.h"
@@ -52,277 +56,276 @@ int clock_gettime(int clk_id, struct timespec *tp)
 }
 #endif
 
+using namespace std::literals;
+
 namespace ceph {
-  namespace time_detail {
-    void real_clock::to_ceph_timespec(const time_point& t,
-                                     struct ceph_timespec& ts) {
-      ts.tv_sec = to_time_t(t);
-      ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
-    }
-    struct ceph_timespec real_clock::to_ceph_timespec(const time_point& t) {
-      struct ceph_timespec ts;
-      to_ceph_timespec(t, ts);
-      return ts;
-    }
-    real_clock::time_point real_clock::from_ceph_timespec(
-      const struct ceph_timespec& ts) {
-      return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-    }
+using std::chrono::seconds;
+using std::chrono::nanoseconds;
+void real_clock::to_ceph_timespec(const time_point& t,
+                                 struct ceph_timespec& ts) {
+  ts.tv_sec = to_time_t(t);
+  ts.tv_nsec = (t.time_since_epoch() % 1s).count();
+}
+struct ceph_timespec real_clock::to_ceph_timespec(const time_point& t) {
+  struct ceph_timespec ts;
+  to_ceph_timespec(t, ts);
+  return ts;
+}
+real_clock::time_point real_clock::from_ceph_timespec(
+  const struct ceph_timespec& ts) {
+  return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
+}
 
-    void coarse_real_clock::to_ceph_timespec(const time_point& t,
-                                            struct ceph_timespec& ts) {
-      ts.tv_sec = to_time_t(t);
-      ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
-    }
-    struct ceph_timespec coarse_real_clock::to_ceph_timespec(
-      const time_point& t) {
-      struct ceph_timespec ts;
-      to_ceph_timespec(t, ts);
-      return ts;
-    }
-    coarse_real_clock::time_point coarse_real_clock::from_ceph_timespec(
-      const struct ceph_timespec& ts) {
-      return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-    }
+void coarse_real_clock::to_ceph_timespec(const time_point& t,
+                                        struct ceph_timespec& ts) {
+  ts.tv_sec = to_time_t(t);
+  ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
+}
+struct ceph_timespec coarse_real_clock::to_ceph_timespec(
+  const time_point& t) {
+  struct ceph_timespec ts;
+  to_ceph_timespec(t, ts);
+  return ts;
+}
+coarse_real_clock::time_point coarse_real_clock::from_ceph_timespec(
+  const struct ceph_timespec& ts) {
+  return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
+}
 
-  }
 
-  using std::chrono::duration_cast;
-  using std::chrono::seconds;
-  using std::chrono::microseconds;
+using std::chrono::duration_cast;
+using std::chrono::seconds;
+using std::chrono::microseconds;
 
-  template<typename Clock,
-          typename std::enable_if<Clock::is_steady>::type*>
-  std::ostream& operator<<(std::ostream& m,
-                          const std::chrono::time_point<Clock>& t) {
-    return m << std::fixed << std::chrono::duration<double>(
-               t.time_since_epoch()).count()
-            << 's';
-  }
+template<typename Clock,
+        typename std::enable_if<Clock::is_steady>::type*>
+std::ostream& operator<<(std::ostream& m,
+                        const std::chrono::time_point<Clock>& t) {
+  return m << std::fixed << std::chrono::duration<double>(
+    t.time_since_epoch()).count()
+          << 's';
+}
 
-  std::ostream& operator<<(std::ostream& m, const timespan& t) {
-    static_assert(std::is_unsigned_v<timespan::rep>);
-    m << std::chrono::duration_cast<std::chrono::seconds>(t).count();
-    if (auto ns = (t % 1s).count(); ns > 0) {
-      char oldfill = m.fill();
-      m.fill('0');
-      m << '.' << std::setw(9) << ns;
-      m.fill(oldfill);
-    }
-    return m << 's';
-  }
+template<typename Clock,
+        typename std::enable_if<!Clock::is_steady>::type*>
+std::ostream& operator<<(std::ostream& m,
+                        const std::chrono::time_point<Clock>& t) {
+  m.setf(std::ios::right);
+  char oldfill = m.fill();
+  m.fill('0');
+  // localtime.  this looks like an absolute time.
+  //  conform to http://en.wikipedia.org/wiki/ISO_8601
+  struct tm bdt;
+  time_t tt = Clock::to_time_t(t);
+  localtime_r(&tt, &bdt);
+  char tz[32] = { 0 };
+  strftime(tz, sizeof(tz), "%z", &bdt);
+  m << std::setw(4) << (bdt.tm_year+1900)  // 2007 -> '07'
+    << '-' << std::setw(2) << (bdt.tm_mon+1)
+    << '-' << std::setw(2) << bdt.tm_mday
+    << 'T'
+    << std::setw(2) << bdt.tm_hour
+    << ':' << std::setw(2) << bdt.tm_min
+    << ':' << std::setw(2) << bdt.tm_sec
+    << "." << std::setw(6) << duration_cast<microseconds>(
+      t.time_since_epoch() % seconds(1)).count()
+    << tz;
+  m.fill(oldfill);
+  m.unsetf(std::ios::right);
+  return m;
+}
 
-  template<typename Clock,
-          typename std::enable_if<!Clock::is_steady>::type*>
-  std::ostream& operator<<(std::ostream& m,
-                          const std::chrono::time_point<Clock>& t) {
-    m.setf(std::ios::right);
-    char oldfill = m.fill();
-    m.fill('0');
-    // localtime.  this looks like an absolute time.
-    //  conform to http://en.wikipedia.org/wiki/ISO_8601
-    struct tm bdt;
-    time_t tt = Clock::to_time_t(t);
-    localtime_r(&tt, &bdt);
-    char tz[32] = { 0 };
-    strftime(tz, sizeof(tz), "%z", &bdt);
-    m << std::setw(4) << (bdt.tm_year+1900)  // 2007 -> '07'
-      << '-' << std::setw(2) << (bdt.tm_mon+1)
-      << '-' << std::setw(2) << bdt.tm_mday
-      << 'T'
-      << std::setw(2) << bdt.tm_hour
-      << ':' << std::setw(2) << bdt.tm_min
-      << ':' << std::setw(2) << bdt.tm_sec
-      << "." << std::setw(6) << duration_cast<microseconds>(
-       t.time_since_epoch() % seconds(1)).count()
-      << tz;
-    m.fill(oldfill);
-    m.unsetf(std::ios::right);
-    return m;
-  }
+template std::ostream&
+operator<< <mono_clock>(std::ostream& m, const mono_time& t);
+template std::ostream&
+operator<< <real_clock>(std::ostream& m, const real_time& t);
+template std::ostream&
+operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t);
+template std::ostream&
+operator<< <coarse_real_clock>(std::ostream& m, const coarse_real_time& t);
 
-  template std::ostream&
-  operator<< <mono_clock>(std::ostream& m, const mono_time& t);
-  template std::ostream&
-  operator<< <real_clock>(std::ostream& m, const real_time& t);
-  template std::ostream&
-  operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t);
-  template std::ostream&
-  operator<< <coarse_real_clock>(std::ostream& m, const coarse_real_time& t);
+std::string timespan_str(timespan t)
+{
+  // FIXME: somebody pretty please make a version of this function
+  // that isn't as lame as this one!
+  uint64_t nsec = std::chrono::nanoseconds(t).count();
+  std::ostringstream ss;
+  if (nsec < 2000000000) {
+    ss << ((float)nsec / 1000000000) << "s";
+    return ss.str();
+  }
+  uint64_t sec = nsec / 1000000000;
+  if (sec < 120) {
+    ss << sec << "s";
+    return ss.str();
+  }
+  uint64_t min = sec / 60;
+  if (min < 120) {
+    ss << min << "m";
+    return ss.str();
+  }
+  uint64_t hr = min / 60;
+  if (hr < 48) {
+    ss << hr << "h";
+    return ss.str();
+  }
+  uint64_t day = hr / 24;
+  if (day < 14) {
+    ss << day << "d";
+    return ss.str();
+  }
+  uint64_t wk = day / 7;
+  if (wk < 12) {
+    ss << wk << "w";
+    return ss.str();
+  }
+  uint64_t mn = day / 30;
+  if (mn < 24) {
+    ss << mn << "M";
+    return ss.str();
+  }
+  uint64_t yr = day / 365;
+  ss << yr << "y";
+  return ss.str();
+}
 
-  std::string timespan_str(timespan t)
-  {
-    // FIXME: somebody pretty please make a version of this function
-    // that isn't as lame as this one!
-    uint64_t nsec = std::chrono::nanoseconds(t).count();
-    ostringstream ss;
-    if (nsec < 2000000000) {
-      ss << ((float)nsec / 1000000000) << "s";
-      return ss.str();
-    }
-    uint64_t sec = nsec / 1000000000;
-    if (sec < 120) {
-      ss << sec << "s";
-      return ss.str();
-    }
-    uint64_t min = sec / 60;
-    if (min < 120) {
-      ss << min << "m";
-      return ss.str();
-    }
-    uint64_t hr = min / 60;
-    if (hr < 48) {
-      ss << hr << "h";
-      return ss.str();
-    }
-    uint64_t day = hr / 24;
-    if (day < 14) {
-      ss << day << "d";
-      return ss.str();
-    }
-    uint64_t wk = day / 7;
-    if (wk < 12) {
-      ss << wk << "w";
-      return ss.str();
-    }
-    uint64_t mn = day / 30;
-    if (mn < 24) {
-      ss << mn << "M";
-      return ss.str();
-    }
-    uint64_t yr = day / 365;
+std::string exact_timespan_str(timespan t)
+{
+  uint64_t nsec = std::chrono::nanoseconds(t).count();
+  uint64_t sec = nsec / 1000000000;
+  nsec %= 1000000000;
+  uint64_t yr = sec / (60 * 60 * 24 * 365);
+  std::ostringstream ss;
+  if (yr) {
     ss << yr << "y";
-    return ss.str();
+    sec -= yr * (60 * 60 * 24 * 365);
+  }
+  uint64_t mn = sec / (60 * 60 * 24 * 30);
+  if (mn >= 3) {
+    ss << mn << "mo";
+    sec -= mn * (60 * 60 * 24 * 30);
+  }
+  uint64_t wk = sec / (60 * 60 * 24 * 7);
+  if (wk >= 2) {
+    ss << wk << "w";
+    sec -= wk * (60 * 60 * 24 * 7);
+  }
+  uint64_t day = sec / (60 * 60 * 24);
+  if (day >= 2) {
+    ss << day << "d";
+    sec -= day * (60 * 60 * 24);
   }
+  uint64_t hr = sec / (60 * 60);
+  if (hr >= 2) {
+    ss << hr << "h";
+    sec -= hr * (60 * 60);
+  }
+  uint64_t min = sec / 60;
+  if (min >= 2) {
+    ss << min << "m";
+    sec -= min * 60;
+  }
+  if (sec) {
+    ss << sec;
+  }
+  if (nsec) {
+    ss << ((float)nsec / 1000000000);
+  }
+  if (sec || nsec) {
+    ss << "s";
+  }
+  return ss.str();
+}
 
-  std::string exact_timespan_str(timespan t)
-  {
-    uint64_t nsec = std::chrono::nanoseconds(t).count();
-    uint64_t sec = nsec / 1000000000;
-    nsec %= 1000000000;
-    uint64_t yr = sec / (60 * 60 * 24 * 365);
-    ostringstream ss;
-    if (yr) {
-      ss << yr << "y";
-      sec -= yr * (60 * 60 * 24 * 365);
-    }
-    uint64_t mn = sec / (60 * 60 * 24 * 30);
-    if (mn >= 3) {
-      ss << mn << "mo";
-      sec -= mn * (60 * 60 * 24 * 30);
-    }
-    uint64_t wk = sec / (60 * 60 * 24 * 7);
-    if (wk >= 2) {
-      ss << wk << "w";
-      sec -= wk * (60 * 60 * 24 * 7);
-    }
-    uint64_t day = sec / (60 * 60 * 24);
-    if (day >= 2) {
-      ss << day << "d";
-      sec -= day * (60 * 60 * 24);
-    }
-    uint64_t hr = sec / (60 * 60);
-    if (hr >= 2) {
-      ss << hr << "h";
-      sec -= hr * (60 * 60);
+std::chrono::seconds parse_timespan(const std::string& s)
+{
+  static std::map<std::string,int> units = {
+    { "s", 1 },
+    { "sec", 1 },
+    { "second", 1 },
+    { "seconds", 1 },
+    { "m", 60 },
+    { "min", 60 },
+    { "minute", 60 },
+    { "minutes", 60 },
+    { "h", 60*60 },
+    { "hr", 60*60 },
+    { "hour", 60*60 },
+    { "hours", 60*60 },
+    { "d", 24*60*60 },
+    { "day", 24*60*60 },
+    { "days", 24*60*60 },
+    { "w", 7*24*60*60 },
+    { "wk", 7*24*60*60 },
+    { "week", 7*24*60*60 },
+    { "weeks", 7*24*60*60 },
+    { "mo", 30*24*60*60 },
+    { "month", 30*24*60*60 },
+    { "months", 30*24*60*60 },
+    { "y", 365*24*60*60 },
+    { "yr", 365*24*60*60 },
+    { "year", 365*24*60*60 },
+    { "years", 365*24*60*60 },
+  };
+
+  auto r = 0s;
+  auto pos = 0u;
+  while (pos < s.size()) {
+    // skip whitespace
+    while (std::isspace(s[pos])) {
+      ++pos;
     }
-    uint64_t min = sec / 60;
-    if (min >= 2) {
-      ss << min << "m";
-      sec -= min * 60;
+    if (pos >= s.size()) {
+      break;
     }
-    if (sec) {
-      ss << sec;
+
+    // consume any digits
+    auto val_start = pos;
+    while (std::isdigit(s[pos])) {
+      ++pos;
     }
-    if (nsec) {
-      ss << ((float)nsec / 1000000000);
+    if (val_start == pos) {
+      throw std::invalid_argument("expected digit");
     }
-    if (sec || nsec) {
-      ss << "s";
+    auto n = s.substr(val_start, pos - val_start);
+    std::string err;
+    auto val = strict_strtoll(n.c_str(), 10, &err);
+    if (err.size()) {
+      throw std::invalid_argument(err);
     }
-    return ss.str();
-  }
-
-  std::chrono::seconds parse_timespan(const std::string& s)
-  {
-    static std::map<string,int> units = {
-      { "s", 1 },
-      { "sec", 1 },
-      { "second", 1 },
-      { "seconds", 1 },
-      { "m", 60 },
-      { "min", 60 },
-      { "minute", 60 },
-      { "minutes", 60 },
-      { "h", 60*60 },
-      { "hr", 60*60 },
-      { "hour", 60*60 },
-      { "hours", 60*60 },
-      { "d", 24*60*60 },
-      { "day", 24*60*60 },
-      { "days", 24*60*60 },
-      { "w", 7*24*60*60 },
-      { "wk", 7*24*60*60 },
-      { "week", 7*24*60*60 },
-      { "weeks", 7*24*60*60 },
-      { "mo", 30*24*60*60 },
-      { "month", 30*24*60*60 },
-      { "months", 30*24*60*60 },
-      { "y", 365*24*60*60 },
-      { "yr", 365*24*60*60 },
-      { "year", 365*24*60*60 },
-      { "years", 365*24*60*60 },
-    };
-
-    auto r = 0s;
-    auto pos = 0u;
-    while (pos < s.size()) {
-      // skip whitespace
-      while (std::isspace(s[pos])) {
-       ++pos;
-      }
-      if (pos >= s.size()) {
-       break;
-      }
-
-      // consume any digits
-      auto val_start = pos;
-      while (std::isdigit(s[pos])) {
-       ++pos;
-      }
-      if (val_start == pos) {
-       throw invalid_argument("expected digit");
-      }
-      string n = s.substr(val_start, pos - val_start);
-      string err;
-      auto val = strict_strtoll(n.c_str(), 10, &err);
-      if (err.size()) {
-       throw invalid_argument(err);
-      }
 
-      // skip whitespace
-      while (std::isspace(s[pos])) {
-       ++pos;
-      }
+    // skip whitespace
+    while (std::isspace(s[pos])) {
+      ++pos;
+    }
 
-      // consume unit
-      auto unit_start = pos;
-      while (std::isalpha(s[pos])) {
-       ++pos;
-      }
-      if (unit_start != pos) {
-       string unit = s.substr(unit_start, pos - unit_start);
-       auto p = units.find(unit);
-       if (p == units.end()) {
-         throw invalid_argument("unrecogized unit '"s + unit + "'");
-       }
-       val *= p->second;
-      } else if (pos < s.size()) {
-       throw invalid_argument("unexpected trailing '"s + s.substr(pos) + "'");
+    // consume unit
+    auto unit_start = pos;
+    while (std::isalpha(s[pos])) {
+      ++pos;
+    }
+    if (unit_start != pos) {
+      auto unit = s.substr(unit_start, pos - unit_start);
+      auto p = units.find(unit);
+      if (p == units.end()) {
+       throw std::invalid_argument("unrecogized unit '"s + unit + "'");
       }
-      r += chrono::seconds(val);
+      val *= p->second;
+    } else if (pos < s.size()) {
+      throw std::invalid_argument("unexpected trailing '"s + s.substr(pos) + "'");
     }
-    return r;
+    r += std::chrono::seconds(val);
   }
+  return r;
+}
+
+}
 
+namespace std {
+ostream& operator<<(ostream& m, const ::ceph::timespan& t) {
+  static_assert(is_unsigned_v<::ceph::timespan::rep>);
+  using seconds_t = chrono::duration<float>;
+  ::fmt::print(m, "{:.9}", chrono::duration_cast<seconds_t>(t));
+  return m;
 }
+} // namespace std
index f6185c882006312228c3a78ce8837fe0db758b62..663d05f8feb2b0f14f5979cb378aa60261ad7514 100644 (file)
 #include <chrono>
 #include <iostream>
 #include <string>
+#include <optional>
 #include <sys/time.h>
 
-#include "include/ceph_assert.h"
-
 #if defined(__APPLE__)
 #include <sys/_types/_timespec.h>
 
 int clock_gettime(int clk_id, struct timespec *tp);
 #endif
 
+#ifdef _WIN32
+#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
+#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
+// MINGW uses the QueryPerformanceCounter API behind the scenes.
+#endif
+
 struct ceph_timespec;
 
 namespace ceph {
-  namespace time_detail {
-    using std::chrono::duration_cast;
-    using std::chrono::seconds;
-    using std::chrono::microseconds;
-    using std::chrono::nanoseconds;
-    // Currently we use a 64-bit count of nanoseconds.
-
-    // We could, if we wished, use a struct holding a uint64_t count
-    // of seconds and a uint32_t count of nanoseconds.
-
-    // At least this way we can change it to something else if we
-    // want.
-    typedef uint64_t rep;
-
-    // A concrete duration, unsigned. The timespan Ceph thinks in.
-    typedef std::chrono::duration<rep, std::nano> timespan;
-
-
-    // Like the above but signed.
-    typedef int64_t signed_rep;
-
-    typedef std::chrono::duration<signed_rep, std::nano> signedspan;
-
-    // We define our own clocks so we can have our choice of all time
-    // sources supported by the operating system. With the standard
-    // library the resolution and cost are unspecified. (For example,
-    // the libc++ system_clock class gives only microsecond
-    // resolution.)
-
-    // One potential issue is that we should accept system_clock
-    // timepoints in user-facing APIs alongside (or instead of)
-    // ceph::real_clock times.
-    class real_clock {
-    public:
-      typedef timespan duration;
-      typedef duration::rep rep;
-      typedef duration::period period;
-      // The second template parameter defaults to the clock's duration
-      // type.
-      typedef std::chrono::time_point<real_clock> time_point;
-      static constexpr const bool is_steady = false;
-
-      static time_point now() noexcept {
-       struct timespec ts;
-       clock_gettime(CLOCK_REALTIME, &ts);
-       return from_timespec(ts);
-      }
-
-      static bool is_zero(const time_point& t) {
-       return (t == time_point::min());
-      }
-
-      static time_point zero() {
-        return time_point::min();
-      }
-
-      // Allow conversion to/from any clock with the same interface as
-      // std::chrono::system_clock)
-      template<typename Clock, typename Duration>
-      static time_point to_system_time_point(
-       const std::chrono::time_point<Clock, Duration>& t) {
-       return time_point(seconds(Clock::to_time_t(t)) +
-                         duration_cast<duration>(t.time_since_epoch() %
-                                                 seconds(1)));
-      }
-      template<typename Clock, typename Duration>
-      static std::chrono::time_point<Clock, Duration> to_system_time_point(
-       const time_point& t) {
-       return (Clock::from_time_t(to_time_t(t)) +
-               duration_cast<Duration>(t.time_since_epoch() % seconds(1)));
-      }
-
-      static time_t to_time_t(const time_point& t) noexcept {
-       return duration_cast<seconds>(t.time_since_epoch()).count();
-      }
-      static time_point from_time_t(const time_t& t) noexcept {
-       return time_point(seconds(t));
-      }
-
-      static void to_timespec(const time_point& t, struct timespec& ts) {
-       ts.tv_sec = to_time_t(t);
-       ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
-      }
-      static struct timespec to_timespec(const time_point& t) {
-       struct timespec ts;
-       to_timespec(t, ts);
-       return ts;
-      }
-      static time_point from_timespec(const struct timespec& ts) {
-       return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-      }
-
-      static void to_ceph_timespec(const time_point& t,
-                                  struct ceph_timespec& ts);
-      static struct ceph_timespec to_ceph_timespec(const time_point& t);
-      static time_point from_ceph_timespec(const struct ceph_timespec& ts);
-
-      static void to_timeval(const time_point& t, struct timeval& tv) {
-       tv.tv_sec = to_time_t(t);
-       tv.tv_usec = duration_cast<microseconds>(t.time_since_epoch() %
-                                                seconds(1)).count();
-      }
-      static struct timeval to_timeval(const time_point& t) {
-       struct timeval tv;
-       to_timeval(t, tv);
-       return tv;
-      }
-      static time_point from_timeval(const struct timeval& tv) {
-       return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
-      }
-
-      static double to_double(const time_point& t) {
-       return std::chrono::duration<double>(t.time_since_epoch()).count();
-      }
-      static time_point from_double(const double d) {
-       return time_point(duration_cast<duration>(
-                           std::chrono::duration<double>(d)));
-      }
-    };
-
-    class coarse_real_clock {
-    public:
-      typedef timespan duration;
-      typedef duration::rep rep;
-      typedef duration::period period;
-      // The second template parameter defaults to the clock's duration
-      // type.
-      typedef std::chrono::time_point<coarse_real_clock> time_point;
-      static constexpr const bool is_steady = false;
-
-      static time_point now() noexcept {
-       struct timespec ts;
+// Currently we use a 64-bit count of nanoseconds.
+
+// We could, if we wished, use a struct holding a uint64_t count
+// of seconds and a uint32_t count of nanoseconds.
+
+// At least this way we can change it to something else if we
+// want.
+typedef uint64_t rep;
+
+
+// duration is the concrete time representation for our code in the
+// case that we are only interested in durations between now and the
+// future. Using it means we don't have to have EVERY function that
+// deals with a duration be a template. We can do so for user-facing
+// APIs, however.
+typedef std::chrono::duration<rep, std::nano> timespan;
+
+
+// Like the above but signed.
+typedef int64_t signed_rep;
+
+// Similar to the above but for durations that can specify
+// differences between now and a time point in the past.
+typedef std::chrono::duration<signed_rep, std::nano> signedspan;
+
+// We define our own clocks so we can have our choice of all time
+// sources supported by the operating system. With the standard
+// library the resolution and cost are unspecified. (For example,
+// the libc++ system_clock class gives only microsecond
+// resolution.)
+
+// One potential issue is that we should accept system_clock
+// timepoints in user-facing APIs alongside (or instead of)
+// ceph::real_clock times.
+
+// High-resolution real-time clock
+class real_clock {
+public:
+  typedef timespan duration;
+  typedef duration::rep rep;
+  typedef duration::period period;
+  // The second template parameter defaults to the clock's duration
+  // type.
+  typedef std::chrono::time_point<real_clock> time_point;
+  static constexpr const bool is_steady = false;
+
+  static time_point now() noexcept {
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    return from_timespec(ts);
+  }
+
+  static bool is_zero(const time_point& t) {
+    return (t == time_point::min());
+  }
+
+  static time_point zero() {
+    return time_point::min();
+  }
+
+  // Allow conversion to/from any clock with the same interface as
+  // std::chrono::system_clock)
+  template<typename Clock, typename Duration>
+  static time_point to_system_time_point(
+    const std::chrono::time_point<Clock, Duration>& t) {
+    return time_point(seconds(Clock::to_time_t(t)) +
+                     std::chrono::duration_cast<duration>(t.time_since_epoch() %
+                                                          std::chrono::seconds(1)));
+  }
+  template<typename Clock, typename Duration>
+  static std::chrono::time_point<Clock, Duration> to_system_time_point(
+    const time_point& t) {
+    return (Clock::from_time_t(to_time_t(t)) +
+           std::chrono::duration_cast<Duration>(t.time_since_epoch() %
+                                                std::chrono::seconds(1)));
+  }
+
+  static time_t to_time_t(const time_point& t) noexcept {
+    return std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count();
+  }
+  static time_point from_time_t(const time_t& t) noexcept {
+    return time_point(std::chrono::seconds(t));
+  }
+
+  static void to_timespec(const time_point& t, struct timespec& ts) {
+    ts.tv_sec = to_time_t(t);
+    ts.tv_nsec = (t.time_since_epoch() % std::chrono::seconds(1)).count();
+  }
+  static struct timespec to_timespec(const time_point& t) {
+    struct timespec ts;
+    to_timespec(t, ts);
+    return ts;
+  }
+  static time_point from_timespec(const struct timespec& ts) {
+    return time_point(std::chrono::seconds(ts.tv_sec) +
+                     std::chrono::nanoseconds(ts.tv_nsec));
+  }
+
+  static void to_ceph_timespec(const time_point& t,
+                              struct ceph_timespec& ts);
+  static struct ceph_timespec to_ceph_timespec(const time_point& t);
+  static time_point from_ceph_timespec(const struct ceph_timespec& ts);
+
+  static void to_timeval(const time_point& t, struct timeval& tv) {
+    tv.tv_sec = to_time_t(t);
+    tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
+      t.time_since_epoch() % std::chrono::seconds(1)).count();
+  }
+  static struct timeval to_timeval(const time_point& t) {
+    struct timeval tv;
+    to_timeval(t, tv);
+    return tv;
+  }
+  static time_point from_timeval(const struct timeval& tv) {
+    return time_point(std::chrono::seconds(tv.tv_sec) +
+                     std::chrono::microseconds(tv.tv_usec));
+  }
+
+  static double to_double(const time_point& t) {
+    return std::chrono::duration<double>(t.time_since_epoch()).count();
+  }
+  static time_point from_double(const double d) {
+    return time_point(std::chrono::duration_cast<duration>(
+                       std::chrono::duration<double>(d)));
+  }
+};
+
+// Low-resolution but preusmably faster real-time clock
+class coarse_real_clock {
+public:
+  typedef timespan duration;
+  typedef duration::rep rep;
+  typedef duration::period period;
+  // The second template parameter defaults to the clock's duration
+  // type.
+  typedef std::chrono::time_point<coarse_real_clock> time_point;
+  static constexpr const bool is_steady = false;
+
+  static time_point now() noexcept {
+    struct timespec ts;
 #if defined(CLOCK_REALTIME_COARSE)
-       // Linux systems have _COARSE clocks.
-       clock_gettime(CLOCK_REALTIME_COARSE, &ts);
+    // Linux systems have _COARSE clocks.
+    clock_gettime(CLOCK_REALTIME_COARSE, &ts);
 #elif defined(CLOCK_REALTIME_FAST)
-       // BSD systems have _FAST clocks.
-       clock_gettime(CLOCK_REALTIME_FAST, &ts);
+    // BSD systems have _FAST clocks.
+    clock_gettime(CLOCK_REALTIME_FAST, &ts);
 #else
-       // And if we find neither, you may wish to consult your system's
-       // documentation.
+    // And if we find neither, you may wish to consult your system's
+    // documentation.
 #warning Falling back to CLOCK_REALTIME, may be slow.
-       clock_gettime(CLOCK_REALTIME, &ts);
+    clock_gettime(CLOCK_REALTIME, &ts);
 #endif
-       return from_timespec(ts);
-      }
-
-      static bool is_zero(const time_point& t) {
-       return (t == time_point::min());
-      }
-
-      static time_point zero() {
-       return time_point::min();
-      }
-
-      static time_t to_time_t(const time_point& t) noexcept {
-       return duration_cast<seconds>(t.time_since_epoch()).count();
-      }
-      static time_point from_time_t(const time_t t) noexcept {
-       return time_point(seconds(t));
-      }
-
-      static void to_timespec(const time_point& t, struct timespec& ts) {
-       ts.tv_sec = to_time_t(t);
-       ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count();
-      }
-      static struct timespec to_timespec(const time_point& t) {
-       struct timespec ts;
-       to_timespec(t, ts);
-       return ts;
-      }
-      static time_point from_timespec(const struct timespec& ts) {
-       return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-      }
-
-      static void to_ceph_timespec(const time_point& t,
-                                  struct ceph_timespec& ts);
-      static struct ceph_timespec to_ceph_timespec(const time_point& t);
-      static time_point from_ceph_timespec(const struct ceph_timespec& ts);
-
-      static void to_timeval(const time_point& t, struct timeval& tv) {
-       tv.tv_sec = to_time_t(t);
-       tv.tv_usec = duration_cast<microseconds>(t.time_since_epoch() %
-                                                seconds(1)).count();
-      }
-      static struct timeval to_timeval(const time_point& t) {
-       struct timeval tv;
-       to_timeval(t, tv);
-       return tv;
-      }
-      static time_point from_timeval(const struct timeval& tv) {
-       return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
-      }
-
-      static double to_double(const time_point& t) {
-       return std::chrono::duration<double>(t.time_since_epoch()).count();
-      }
-      static time_point from_double(const double d) {
-       return time_point(duration_cast<duration>(
-                           std::chrono::duration<double>(d)));
-      }
-    };
-
-    class mono_clock {
-    public:
-      typedef timespan duration;
-      typedef duration::rep rep;
-      typedef duration::period period;
-      typedef std::chrono::time_point<mono_clock> time_point;
-      static constexpr const bool is_steady = true;
-
-      static time_point now() noexcept {
-       struct timespec ts;
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-       return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-      }
-
-      static bool is_zero(const time_point& t) {
-        return (t == time_point::min());
-      }
-
-      static time_point zero() {
-        return time_point::min();
-      }
-
-      // A monotonic clock's timepoints are only meaningful to the
-      // computer on which they were generated. Thus having an
-      // optional skew is meaningless.
-    };
-
-    class coarse_mono_clock {
-    public:
-      typedef timespan duration;
-      typedef duration::rep rep;
-      typedef duration::period period;
-      typedef std::chrono::time_point<coarse_mono_clock> time_point;
-      static constexpr const bool is_steady = true;
-
-      static time_point now() noexcept {
-       struct timespec ts;
+    return from_timespec(ts);
+  }
+
+  static bool is_zero(const time_point& t) {
+    return (t == time_point::min());
+  }
+
+  static time_point zero() {
+    return time_point::min();
+  }
+
+  static time_t to_time_t(const time_point& t) noexcept {
+    return std::chrono::duration_cast<std::chrono::seconds>(
+      t.time_since_epoch()).count();
+  }
+  static time_point from_time_t(const time_t t) noexcept {
+    return time_point(std::chrono::seconds(t));
+  }
+
+  static void to_timespec(const time_point& t, struct timespec& ts) {
+    ts.tv_sec = to_time_t(t);
+    ts.tv_nsec = (t.time_since_epoch() % std::chrono::seconds(1)).count();
+  }
+  static struct timespec to_timespec(const time_point& t) {
+    struct timespec ts;
+    to_timespec(t, ts);
+    return ts;
+  }
+  static time_point from_timespec(const struct timespec& ts) {
+    return time_point(std::chrono::seconds(ts.tv_sec) +
+                     std::chrono::nanoseconds(ts.tv_nsec));
+  }
+
+  static void to_ceph_timespec(const time_point& t,
+                              struct ceph_timespec& ts);
+  static struct ceph_timespec to_ceph_timespec(const time_point& t);
+  static time_point from_ceph_timespec(const struct ceph_timespec& ts);
+
+  static void to_timeval(const time_point& t, struct timeval& tv) {
+    tv.tv_sec = to_time_t(t);
+    tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
+      t.time_since_epoch() % std::chrono::seconds(1)).count();
+  }
+  static struct timeval to_timeval(const time_point& t) {
+    struct timeval tv;
+    to_timeval(t, tv);
+    return tv;
+  }
+  static time_point from_timeval(const struct timeval& tv) {
+    return time_point(std::chrono::seconds(tv.tv_sec) +
+                     std::chrono::microseconds(tv.tv_usec));
+  }
+
+  static double to_double(const time_point& t) {
+    return std::chrono::duration<double>(t.time_since_epoch()).count();
+  }
+  static time_point from_double(const double d) {
+    return time_point(std::chrono::duration_cast<duration>(
+                       std::chrono::duration<double>(d)));
+  }
+};
+
+// High-resolution monotonic clock
+class mono_clock {
+public:
+  typedef timespan duration;
+  typedef duration::rep rep;
+  typedef duration::period period;
+  typedef std::chrono::time_point<mono_clock> time_point;
+  static constexpr const bool is_steady = true;
+
+  static time_point now() noexcept {
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return time_point(std::chrono::seconds(ts.tv_sec) +
+                     std::chrono::nanoseconds(ts.tv_nsec));
+  }
+
+  static bool is_zero(const time_point& t) {
+    return (t == time_point::min());
+  }
+
+  static time_point zero() {
+    return time_point::min();
+  }
+};
+
+// Low-resolution but, I would hope or there's no point, faster
+// monotonic clock
+class coarse_mono_clock {
+public:
+  typedef timespan duration;
+  typedef duration::rep rep;
+  typedef duration::period period;
+  typedef std::chrono::time_point<coarse_mono_clock> time_point;
+  static constexpr const bool is_steady = true;
+
+  static time_point now() noexcept {
+    struct timespec ts;
 #if defined(CLOCK_MONOTONIC_COARSE)
-       // Linux systems have _COARSE clocks.
-       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+    // Linux systems have _COARSE clocks.
+    clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
 #elif defined(CLOCK_MONOTONIC_FAST)
-       // BSD systems have _FAST clocks.
-       clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
+    // BSD systems have _FAST clocks.
+    clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
 #else
-       // And if we find neither, you may wish to consult your system's
-       // documentation.
+    // And if we find neither, you may wish to consult your system's
+    // documentation.
 #warning Falling back to CLOCK_MONOTONIC, may be slow.
-       clock_gettime(CLOCK_MONOTONIC, &ts);
+    clock_gettime(CLOCK_MONOTONIC, &ts);
 #endif
-       return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
-      }
-
-      static bool is_zero(const time_point& t) {
-        return (t == time_point::min());
-      }
-
-      static time_point zero() {
-        return time_point::min();
-      }
-    };
-
-    // So that our subtractions produce negative spans rather than
-    // arithmetic underflow.
-    namespace {
-      template<typename Rep1, typename Period1, typename Rep2,
-              typename Period2>
-      inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
-                            std::chrono::duration<Rep2, Period2> subtrahend)
-       -> typename std::common_type<
-         std::chrono::duration<typename std::make_signed<Rep1>::type,
-                               Period1>,
-         std::chrono::duration<typename std::make_signed<Rep2>::type,
-                               Period2> >::type {
-       // Foo.
-       using srep =
-         typename std::common_type<
-           std::chrono::duration<typename std::make_signed<Rep1>::type,
-                                 Period1>,
-           std::chrono::duration<typename std::make_signed<Rep2>::type,
-                                 Period2> >::type;
-       return srep(srep(minuend).count() - srep(subtrahend).count());
-      }
-
-      template<typename Clock, typename Duration1, typename Duration2>
-      inline auto difference(
-       typename std::chrono::time_point<Clock, Duration1> minuend,
-       typename std::chrono::time_point<Clock, Duration2> subtrahend)
-       -> typename std::common_type<
-         std::chrono::duration<typename std::make_signed<
-                                 typename Duration1::rep>::type,
-                               typename Duration1::period>,
-         std::chrono::duration<typename std::make_signed<
-                                 typename Duration2::rep>::type,
-                               typename Duration2::period> >::type {
-       return difference(minuend.time_since_epoch(),
-                         subtrahend.time_since_epoch());
-      }
-    }
-  } // namespace time_detail
-
-  // duration is the concrete time representation for our code in the
-  // case that we are only interested in durations between now and the
-  // future. Using it means we don't have to have EVERY function that
-  // deals with a duration be a template. We can do so for user-facing
-  // APIs, however.
-  using time_detail::timespan;
-
-  // Similar to the above but for durations that can specify
-  // differences between now and a time point in the past.
-  using time_detail::signedspan;
-
-  // High-resolution real-time clock
-  using time_detail::real_clock;
-
-  // Low-resolution but preusmably faster real-time clock
-  using time_detail::coarse_real_clock;
-
-
-  // High-resolution monotonic clock
-  using time_detail::mono_clock;
-
-  // Low-resolution but, I would hope or there's no point, faster
-  // monotonic clock
-  using time_detail::coarse_mono_clock;
-
-  // Please note that the coarse clocks are disjoint. You cannot
-  // subtract a real_clock timepoint from a coarse_real_clock
-  // timepoint as, from C++'s perspective, they are disjoint types.
-
-  // This is not necessarily bad. If I sample a mono_clock and then a
-  // coarse_mono_clock, the coarse_mono_clock's time could potentially
-  // be previous to the mono_clock's time (just due to differing
-  // resolution) which would be Incorrect.
-
-  // This is not horrible, though, since you can use an idiom like
-  // mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap
-  // and rewrap if you know what you're doing.
-
-
-  // Actual wall-clock times
-  typedef real_clock::time_point real_time;
-  typedef coarse_real_clock::time_point coarse_real_time;
-
-  // Monotonic times should never be serialized or communicated
-  // between machines, since they are incomparable. Thus we also don't
-  // make any provision for converting between
-  // std::chrono::steady_clock time and ceph::mono_clock time.
-  typedef mono_clock::time_point mono_time;
-  typedef coarse_mono_clock::time_point coarse_mono_time;
-
-  template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
-  auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
-            const std::chrono::duration<Rep2, Ratio2>& precision) ->
-    typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
-                             std::chrono::duration<Rep2, Ratio2> >::type {
-    return duration - (duration % precision);
-  }
-
-  template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
-  auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
-           const std::chrono::duration<Rep2, Ratio2>& precision) ->
-    typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
-                             std::chrono::duration<Rep2, Ratio2> >::type {
-    auto tmod = duration % precision;
-    return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
-  }
-
-  template<typename Clock, typename Duration, typename Rep, typename Ratio>
-  auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
-            const std::chrono::duration<Rep, Ratio>& precision) ->
-    std::chrono::time_point<Clock,
-                           typename std::common_type<
-                             Duration, std::chrono::duration<Rep, Ratio>
-                             >::type> {
-    return std::chrono::time_point<
-      Clock, typename std::common_type<
-       Duration, std::chrono::duration<Rep, Ratio> >::type>(
-         floor(timepoint.time_since_epoch(), precision));
-  }
-  template<typename Clock, typename Duration, typename Rep, typename Ratio>
-  auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
-           const std::chrono::duration<Rep, Ratio>& precision) ->
-    std::chrono::time_point<Clock,
-                           typename std::common_type<
-                             Duration,
-                             std::chrono::duration<Rep, Ratio> >::type> {
-    return std::chrono::time_point<
-      Clock, typename std::common_type<
-       Duration, std::chrono::duration<Rep, Ratio> >::type>(
-         ceil(timepoint.time_since_epoch(), precision));
-  }
-
-  namespace {
-    inline timespan make_timespan(const double d) {
-      return std::chrono::duration_cast<timespan>(
-       std::chrono::duration<double>(d));
-    }
-  }
-
-  std::ostream& operator<<(std::ostream& m, const timespan& t);
-  template<typename Clock,
-          typename std::enable_if<!Clock::is_steady>::type* = nullptr>
-  std::ostream& operator<<(std::ostream& m,
-                          const std::chrono::time_point<Clock>& t);
-  template<typename Clock,
-          typename std::enable_if<Clock::is_steady>::type* = nullptr>
-  std::ostream& operator<<(std::ostream& m,
-                          const std::chrono::time_point<Clock>& t);
-
-  // The way std::chrono handles the return type of subtraction is not
-  // wonderful. The difference of two unsigned types SHOULD be signed.
-
-  namespace {
-    inline signedspan operator -(real_time minuend,
-                                real_time subtrahend) {
-      return time_detail::difference(minuend, subtrahend);
-    }
-
-    inline signedspan operator -(coarse_real_time minuend,
-                                coarse_real_time subtrahend) {
-      return time_detail::difference(minuend, subtrahend);
-    }
-
-    inline signedspan operator -(mono_time minuend,
-                                mono_time subtrahend) {
-      return time_detail::difference(minuend, subtrahend);
-    }
-
-    inline signedspan operator -(coarse_mono_time minuend,
-                                coarse_mono_time subtrahend) {
-      return time_detail::difference(minuend, subtrahend);
-    }
-  }
-
-  // We could add specializations of time_point - duration and
-  // time_point + duration to assert on overflow, but I don't think we
-  // should.
+    return time_point(std::chrono::seconds(ts.tv_sec) +
+                     std::chrono::nanoseconds(ts.tv_nsec));
+  }
+
+  static bool is_zero(const time_point& t) {
+    return (t == time_point::min());
+  }
+
+  static time_point zero() {
+    return time_point::min();
+  }
+};
+
+namespace time_detail {
+// So that our subtractions produce negative spans rather than
+// arithmetic underflow.
+template<typename Rep1, typename Period1, typename Rep2,
+        typename Period2>
+inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
+                      std::chrono::duration<Rep2, Period2> subtrahend)
+  -> typename std::common_type<
+  std::chrono::duration<typename std::make_signed<Rep1>::type,
+                       Period1>,
+  std::chrono::duration<typename std::make_signed<Rep2>::type,
+                       Period2> >::type {
+  // Foo.
+  using srep =
+    typename std::common_type<
+      std::chrono::duration<typename std::make_signed<Rep1>::type,
+                           Period1>,
+    std::chrono::duration<typename std::make_signed<Rep2>::type,
+                         Period2> >::type;
+  return srep(srep(minuend).count() - srep(subtrahend).count());
+}
+
+template<typename Clock, typename Duration1, typename Duration2>
+inline auto difference(
+  typename std::chrono::time_point<Clock, Duration1> minuend,
+  typename std::chrono::time_point<Clock, Duration2> subtrahend)
+  -> typename std::common_type<
+  std::chrono::duration<typename std::make_signed<
+                         typename Duration1::rep>::type,
+                       typename Duration1::period>,
+  std::chrono::duration<typename std::make_signed<
+                         typename Duration2::rep>::type,
+                       typename Duration2::period> >::type {
+  return difference(minuend.time_since_epoch(),
+                   subtrahend.time_since_epoch());
+}
+}
+
+// Please note that the coarse clocks are disjoint. You cannot
+// subtract a real_clock timepoint from a coarse_real_clock
+// timepoint as, from C++'s perspective, they are disjoint types.
+
+// This is not necessarily bad. If I sample a mono_clock and then a
+// coarse_mono_clock, the coarse_mono_clock's time could potentially
+// be previous to the mono_clock's time (just due to differing
+// resolution) which would be Incorrect.
+
+// This is not horrible, though, since you can use an idiom like
+// mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap
+// and rewrap if you know what you're doing.
+
+
+// Actual wall-clock times
+typedef real_clock::time_point real_time;
+typedef coarse_real_clock::time_point coarse_real_time;
+
+// Monotonic times should never be serialized or communicated
+// between machines, since they are incomparable. Thus we also don't
+// make any provision for converting between
+// std::chrono::steady_clock time and ceph::mono_clock time.
+typedef mono_clock::time_point mono_time;
+typedef coarse_mono_clock::time_point coarse_mono_time;
+
+template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
+auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
+          const std::chrono::duration<Rep2, Ratio2>& precision) ->
+  typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
+                           std::chrono::duration<Rep2, Ratio2> >::type {
+  return duration - (duration % precision);
+}
+
+template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
+auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
+         const std::chrono::duration<Rep2, Ratio2>& precision) ->
+  typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
+                           std::chrono::duration<Rep2, Ratio2> >::type {
+  auto tmod = duration % precision;
+  return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
+}
+
+template<typename Clock, typename Duration, typename Rep, typename Ratio>
+auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
+          const std::chrono::duration<Rep, Ratio>& precision) ->
+  std::chrono::time_point<Clock,
+                         typename std::common_type<
+                           Duration, std::chrono::duration<Rep, Ratio>
+                           >::type> {
+  return std::chrono::time_point<
+    Clock, typename std::common_type<
+      Duration, std::chrono::duration<Rep, Ratio> >::type>(
+       floor(timepoint.time_since_epoch(), precision));
+}
+template<typename Clock, typename Duration, typename Rep, typename Ratio>
+auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
+         const std::chrono::duration<Rep, Ratio>& precision) ->
+  std::chrono::time_point<Clock,
+                         typename std::common_type<
+                           Duration,
+                           std::chrono::duration<Rep, Ratio> >::type> {
+  return std::chrono::time_point<
+    Clock, typename std::common_type<
+      Duration, std::chrono::duration<Rep, Ratio> >::type>(
+       ceil(timepoint.time_since_epoch(), precision));
+}
+
+inline timespan make_timespan(const double d) {
+  return std::chrono::duration_cast<timespan>(
+    std::chrono::duration<double>(d));
+}
+inline std::optional<timespan> maybe_timespan(const double d) {
+  return d ? std::make_optional(make_timespan(d)) : std::nullopt;
+}
+
+template<typename Clock,
+        typename std::enable_if<!Clock::is_steady>::type* = nullptr>
+std::ostream& operator<<(std::ostream& m,
+                        const std::chrono::time_point<Clock>& t);
+template<typename Clock,
+        typename std::enable_if<Clock::is_steady>::type* = nullptr>
+std::ostream& operator<<(std::ostream& m,
+                        const std::chrono::time_point<Clock>& t);
+
+// The way std::chrono handles the return type of subtraction is not
+// wonderful. The difference of two unsigned types SHOULD be signed.
+
+inline signedspan operator -(real_time minuend,
+                            real_time subtrahend) {
+  return time_detail::difference(minuend, subtrahend);
+}
+
+inline signedspan operator -(coarse_real_time minuend,
+                            coarse_real_time subtrahend) {
+  return time_detail::difference(minuend, subtrahend);
+}
 
+inline signedspan operator -(mono_time minuend,
+                            mono_time subtrahend) {
+  return time_detail::difference(minuend, subtrahend);
+}
+
+inline signedspan operator -(coarse_mono_time minuend,
+                            coarse_mono_time subtrahend) {
+  return time_detail::difference(minuend, subtrahend);
+}
 
+// We could add specializations of time_point - duration and
+// time_point + duration to assert on overflow, but I don't think we
+// should.
 inline timespan abs(signedspan z) {
   return z > signedspan::zero() ?
     std::chrono::duration_cast<timespan>(z) :
@@ -508,8 +495,8 @@ struct converts_to_timespec : std::false_type {};
 
 template <typename Clock>
 struct converts_to_timespec<Clock, std::void_t<decltype(
-    Clock::from_timespec(Clock::to_timespec(
-        std::declval<typename Clock::time_point>()))
+  Clock::from_timespec(Clock::to_timespec(
+                        std::declval<typename Clock::time_point>()))
   )>> : std::true_type {};
 
 template <typename Clock>
@@ -531,4 +518,8 @@ static Rep to_microseconds(T t) {
 
 } // namespace ceph
 
+namespace std {
+ostream& operator<<(ostream& m, const ::ceph::timespan& t);
+}
+
 #endif // COMMON_CEPH_TIME_H