#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"
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);
}
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; }
,
"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
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
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;
// 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;
}
// 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');
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();
}
// 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');
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;
}
// 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');
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);
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');
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();
}
- 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));
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;
*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) {
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