]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/include/utime.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / include / utime.h
index bc9f6429a12c1be8e4198b844886b40e5e39f2f4..fad66af7939ad65750723e57ddb4eb4449dedcb4 100644 (file)
 #include <time.h>
 #include <errno.h>
 
+#if defined(WITH_SEASTAR)
+#include <seastar/core/lowres_clock.hh>
+#endif
+
+#include "include/compat.h"
 #include "include/types.h"
 #include "include/timegm.h"
 #include "common/strtol.h"
@@ -77,6 +82,27 @@ public:
   explicit utime_t(const std::chrono::time_point<Clock>& t)
     : utime_t(Clock::to_timespec(t)) {} // forward to timespec ctor
 
+  template<class Rep, class Period>
+  explicit utime_t(const std::chrono::duration<Rep, Period>& dur) {
+    using common_t = std::common_type_t<Rep, int>;
+    tv.tv_sec = std::max<common_t>(std::chrono::duration_cast<std::chrono::seconds>(dur).count(), 0);
+    tv.tv_nsec = std::max<common_t>((std::chrono::duration_cast<std::chrono::nanoseconds>(dur) %
+                                    std::chrono::seconds(1)).count(), 0);
+  }
+#if defined(WITH_SEASTAR)
+  explicit utime_t(const seastar::lowres_system_clock::time_point& t) {
+    tv.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(
+        t.time_since_epoch()).count();
+    tv.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(
+        t.time_since_epoch() % std::chrono::seconds(1)).count();
+  }
+  explicit operator seastar::lowres_system_clock::time_point() const noexcept {
+    using clock_t = seastar::lowres_system_clock;
+    return clock_t::time_point{std::chrono::duration_cast<clock_t::duration>(
+      std::chrono::seconds{tv.tv_sec} + std::chrono::nanoseconds{tv.tv_nsec})};
+  }
+#endif
+
   utime_t(const struct timeval &v) {
     set_from_timeval(&v);
   }
@@ -87,19 +113,19 @@ public:
     ts->tv_sec = tv.tv_sec;
     ts->tv_nsec = tv.tv_nsec;
   }
-  void set_from_double(double d) { 
+  void set_from_double(double d) {
     tv.tv_sec = (__u32)trunc(d);
     tv.tv_nsec = (__u32)((d - (double)tv.tv_sec) * 1000000000.0);
   }
 
-  real_time to_real_time() const {
+  ceph::real_time to_real_time() const {
     ceph_timespec ts;
     encode_timeval(&ts);
     return ceph::real_clock::from_ceph_timespec(ts);
   }
 
   // accessors
-  time_t        sec()  const { return tv.tv_sec; } 
+  time_t        sec()  const { return tv.tv_sec; }
   long          usec() const { return tv.tv_nsec/1000; }
   int           nsec() const { return tv.tv_nsec; }
 
@@ -130,7 +156,7 @@ public:
       ,
       "utime_t have padding");
   }
-  void encode(bufferlist &bl) const {
+  void encode(ceph::buffer::list &bl) const {
 #if defined(CEPH_LITTLE_ENDIAN)
     bl.append((char *)(this), sizeof(__u32) + sizeof(__u32));
 #else
@@ -139,7 +165,7 @@ public:
     encode(tv.tv_nsec, bl);
 #endif
   }
-  void decode(bufferlist::const_iterator &p) {
+  void decode(ceph::buffer::list::const_iterator &p) {
 #if defined(CEPH_LITTLE_ENDIAN)
     p.copy(sizeof(__u32) + sizeof(__u32), (char *)(this));
 #else
@@ -154,7 +180,9 @@ public:
     denc(v.tv.tv_nsec, p);
   }
 
-
+  void dump(ceph::Formatter *f) const;
+  static void generate_test_instances(std::list<utime_t*>& o);
+  
   void encode_timeval(struct ceph_timespec *t) const {
     t->tv_sec = tv.tv_sec;
     t->tv_nsec = tv.tv_nsec;
@@ -196,7 +224,7 @@ public:
 
   // cast to double
   operator double() const {
-    return (double)sec() + ((double)nsec() / 1000000000.0L);
+    return (double)sec() + ((double)nsec() / 1000000000.0f);
   }
   operator ceph_timespec() const {
     ceph_timespec ts;
@@ -212,7 +240,7 @@ public:
   }
 
   // output
-  ostream& gmtime(ostream& out) const {
+  std::ostream& gmtime(std::ostream& out, bool legacy_form=false) const {
     out.setf(std::ios::right);
     char oldfill = out.fill();
     out.fill('0');
@@ -221,15 +249,19 @@ public:
       out << (long)sec() << "." << std::setw(6) << usec();
     } else {
       // this looks like an absolute time.
-      //  aim for http://en.wikipedia.org/wiki/ISO_8601
+      //  conform to http://en.wikipedia.org/wiki/ISO_8601
       struct tm bdt;
       time_t tt = sec();
       gmtime_r(&tt, &bdt);
       out << std::setw(4) << (bdt.tm_year+1900)  // 2007 -> '07'
          << '-' << std::setw(2) << (bdt.tm_mon+1)
-         << '-' << std::setw(2) << bdt.tm_mday
-         << ' '
-         << std::setw(2) << bdt.tm_hour
+         << '-' << std::setw(2) << bdt.tm_mday;
+      if (legacy_form) {
+       out << ' ';
+      } else {
+       out << 'T';
+      }
+      out << std::setw(2) << bdt.tm_hour
          << ':' << std::setw(2) << bdt.tm_min
          << ':' << std::setw(2) << bdt.tm_sec;
       out << "." << std::setw(6) << usec();
@@ -241,7 +273,7 @@ public:
   }
 
   // output
-  ostream& gmtime_nsec(ostream& out) const {
+  std::ostream& gmtime_nsec(std::ostream& out) const {
     out.setf(std::ios::right);
     char oldfill = out.fill();
     out.fill('0');
@@ -250,14 +282,14 @@ public:
       out << (long)sec() << "." << std::setw(6) << usec();
     } else {
       // this looks like an absolute time.
-      //  aim for http://en.wikipedia.org/wiki/ISO_8601
+      //  conform to http://en.wikipedia.org/wiki/ISO_8601
       struct tm bdt;
       time_t tt = sec();
       gmtime_r(&tt, &bdt);
       out << 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;
@@ -270,7 +302,7 @@ public:
   }
 
   // output
-  ostream& asctime(ostream& out) const {
+  std::ostream& asctime(std::ostream& out) const {
     out.setf(std::ios::right);
     char oldfill = out.fill();
     out.fill('0');
@@ -279,7 +311,6 @@ public:
       out << (long)sec() << "." << std::setw(6) << usec();
     } else {
       // this looks like an absolute time.
-      //  aim for http://en.wikipedia.org/wiki/ISO_8601
       struct tm bdt;
       time_t tt = sec();
       gmtime_r(&tt, &bdt);
@@ -295,8 +326,8 @@ public:
     out.unsetf(std::ios::right);
     return out;
   }
-  
-  ostream& localtime(ostream& out) const {
+
+  std::ostream& localtime(std::ostream& out, bool legacy_form=false) const {
     out.setf(std::ios::right);
     char oldfill = out.fill();
     out.fill('0');
@@ -305,50 +336,38 @@ public:
       out << (long)sec() << "." << std::setw(6) << usec();
     } else {
       // this looks like an absolute time.
-      //  aim for http://en.wikipedia.org/wiki/ISO_8601
+      //  conform to http://en.wikipedia.org/wiki/ISO_8601
       struct tm bdt;
       time_t tt = sec();
       localtime_r(&tt, &bdt);
       out << std::setw(4) << (bdt.tm_year+1900)  // 2007 -> '07'
          << '-' << std::setw(2) << (bdt.tm_mon+1)
-         << '-' << std::setw(2) << bdt.tm_mday
-         << ' '
-         << std::setw(2) << bdt.tm_hour
+         << '-' << std::setw(2) << bdt.tm_mday;
+      if (legacy_form) {
+       out << ' ';
+      } else {
+       out << 'T';
+      }
+      out << std::setw(2) << bdt.tm_hour
          << ':' << std::setw(2) << bdt.tm_min
          << ':' << std::setw(2) << bdt.tm_sec;
       out << "." << std::setw(6) << usec();
-      //out << '_' << bdt.tm_zone;
+      if (!legacy_form) {
+       char buf[32] = { 0 };
+       strftime(buf, sizeof(buf), "%z", &bdt);
+       out << buf;
+      }
     }
     out.fill(oldfill);
     out.unsetf(std::ios::right);
     return out;
   }
 
-  int sprintf(char *out, int outlen) const {
-    struct tm bdt;
-    time_t tt = sec();
-    localtime_r(&tt, &bdt);
-
-    return ::snprintf(out, outlen,
-                   "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
-                   bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
-                   bdt.tm_hour, bdt.tm_min, bdt.tm_sec, usec());
-  }
-
-  static int snprintf(char *out, int outlen, time_t tt) {
-    struct tm bdt;
-    localtime_r(&tt, &bdt);
-
-    return ::snprintf(out, outlen,
-        "%04d-%02d-%02d %02d:%02d:%02d",
-        bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
-        bdt.tm_hour, bdt.tm_min, bdt.tm_sec);
-  }
-
   static int invoke_date(const std::string& date_str, utime_t *result) {
      char buf[256];
 
-     SubProcess bin_date("/bin/date", SubProcess::CLOSE, SubProcess::PIPE, SubProcess::KEEP);
+     SubProcess bin_date("/bin/date", SubProcess::CLOSE, SubProcess::PIPE,
+                        SubProcess::KEEP);
      bin_date.add_cmd_args("-d", date_str.c_str(), "+%s %N", NULL);
 
      int r = bin_date.spawn();
@@ -371,8 +390,9 @@ public:
   }
 
 
-  static int parse_date(const string& date, uint64_t *epoch, uint64_t *nsec,
-                        string *out_date=NULL, string *out_time=NULL) {
+  static int parse_date(const std::string& date, uint64_t *epoch, uint64_t *nsec,
+                        std::string *out_date=nullptr,
+                       std::string *out_time=nullptr) {
     struct tm tm;
     memset(&tm, 0, sizeof(tm));
 
@@ -381,23 +401,51 @@ public:
 
     const char *p = strptime(date.c_str(), "%Y-%m-%d", &tm);
     if (p) {
-      if (*p == ' ') {
+      if (*p == ' ' || *p == 'T') {
        p++;
-       p = strptime(p, " %H:%M:%S", &tm);
-       if (!p)
+       // strptime doesn't understand fractional/decimal seconds, and
+       // it also only takes format chars or literals, so we have to
+       // get creative.
+       char fmt[32] = {0};
+       strncpy(fmt, p, sizeof(fmt) - 1);
+       fmt[0] = '%';
+       fmt[1] = 'H';
+       fmt[2] = ':';
+       fmt[3] = '%';
+       fmt[4] = 'M';
+       fmt[6] = '%';
+       fmt[7] = 'S';
+       const char *subsec = 0;
+       char *q = fmt + 8;
+       if (*q == '.') {
+         ++q;
+         subsec = p + 9;
+         q = fmt + 9;
+         while (*q && isdigit(*q)) {
+           ++q;
+         }
+       }
+       // look for tz...
+       if (*q == '-' || *q == '+') {
+         *q = '%';
+         *(q+1) = 'z';
+         *(q+2) = 0;
+       }
+       p = strptime(p, fmt, &tm);
+       if (!p) {
          return -EINVAL;
-        if (nsec && *p == '.') {
-          ++p;
+       }
+        if (nsec && subsec) {
           unsigned i;
           char buf[10]; /* 9 digit + null termination */
-          for (i = 0; (i < sizeof(buf) - 1) && isdigit(*p); ++i, ++p) {
-            buf[i] = *p;
+          for (i = 0; (i < sizeof(buf) - 1) && isdigit(*subsec); ++i, ++subsec) {
+            buf[i] = *subsec;
           }
           for (; i < sizeof(buf) - 1; ++i) {
             buf[i] = '0';
           }
           buf[i] = '\0';
-          string err;
+         std::string err;
           *nsec = (uint64_t)strict_strtol(buf, 10, &err);
           if (!err.empty()) {
             return -EINVAL;
@@ -418,25 +466,38 @@ public:
         *nsec = (uint64_t)usec * 1000;
       }
     }
+
+    #ifndef _WIN32
+    // apply the tm_gmtoff manually below, since none of mktime,
+    // gmtime, and localtime seem to do it.  zero it out here just in
+    // case some other libc *does* apply it.  :(
+    auto gmtoff = tm.tm_gmtoff;
+    tm.tm_gmtoff = 0;
+    #else
+    auto gmtoff = _timezone;
+    #endif /* _WIN32 */
+
     time_t t = internal_timegm(&tm);
     if (epoch)
       *epoch = (uint64_t)t;
 
+    *epoch -= gmtoff;
+
     if (out_date) {
       char buf[32];
-      strftime(buf, sizeof(buf), "%F", &tm);
+      strftime(buf, sizeof(buf), "%Y-%m-%d", &tm);
       *out_date = buf;
     }
     if (out_time) {
       char buf[32];
-      strftime(buf, sizeof(buf), "%T", &tm);
+      strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
       *out_time = buf;
     }
 
     return 0;
   }
 
-  bool parse(const string& s) {
+  bool parse(const std::string& s) {
     uint64_t epoch, nsec;
     int r = parse_date(s, &epoch, &nsec);
     if (r < 0) {
@@ -535,7 +596,7 @@ inline std::ostream& operator<<(std::ostream& out, const utime_t& t)
 
 inline std::string utimespan_str(const utime_t& age) {
   auto age_ts = ceph::timespan(age.nsec()) + std::chrono::seconds(age.sec());
-  return timespan_str(age_ts);
+  return ceph::timespan_str(age_ts);
 }
 
 #endif