]>
git.proxmox.com Git - ceph.git/blob - ceph/src/include/utime.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
23 #include "include/types.h"
24 #include "include/timegm.h"
25 #include "common/strtol.h"
26 #include "common/ceph_time.h"
27 #include "common/safe_io.h"
28 #include "common/SubProcess.h"
29 #include "include/denc.h"
35 inline __u32
cap_to_u32_max(__u64 t
) {
36 return std::min(t
, (__u64
)std::numeric_limits
<uint32_t>::max());
38 /* WARNING: If add member in utime_t, please make sure the encode/decode function
39 * work well. For little-endian machine, we should make sure there is no padding
40 * in 32-bit machine and 64-bit machine.
41 * You should also modify the padding_check function.
46 __u32 tv_sec
, tv_nsec
;
50 bool is_zero() const {
51 return (tv
.tv_sec
== 0) && (tv
.tv_nsec
== 0);
55 if (tv
.tv_nsec
> 1000000000ul) {
56 tv
.tv_sec
= cap_to_u32_max(tv
.tv_sec
+ tv
.tv_nsec
/ (1000000000ul));
57 tv
.tv_nsec
%= 1000000000ul;
62 utime_t() { tv
.tv_sec
= 0; tv
.tv_nsec
= 0; }
63 utime_t(time_t s
, int n
) { tv
.tv_sec
= s
; tv
.tv_nsec
= n
; normalize(); }
64 utime_t(const struct ceph_timespec
&v
) {
67 utime_t(const struct timespec v
)
69 // NOTE: this is used by ceph_clock_now() so should be kept
70 // as thin as possible.
72 tv
.tv_nsec
= v
.tv_nsec
;
74 // conversion from ceph::real_time/coarse_real_time
75 template <typename Clock
, typename
std::enable_if_t
<
76 ceph::converts_to_timespec_v
<Clock
>>* = nullptr>
77 explicit utime_t(const std::chrono::time_point
<Clock
>& t
)
78 : utime_t(Clock::to_timespec(t
)) {} // forward to timespec ctor
80 utime_t(const struct timeval
&v
) {
83 utime_t(const struct timeval
*v
) {
86 void to_timespec(struct timespec
*ts
) const {
87 ts
->tv_sec
= tv
.tv_sec
;
88 ts
->tv_nsec
= tv
.tv_nsec
;
90 void set_from_double(double d
) {
91 tv
.tv_sec
= (__u32
)trunc(d
);
92 tv
.tv_nsec
= (__u32
)((d
- (double)tv
.tv_sec
) * 1000000000.0);
95 real_time
to_real_time() const {
98 return ceph::real_clock::from_ceph_timespec(ts
);
102 time_t sec() const { return tv
.tv_sec
; }
103 long usec() const { return tv
.tv_nsec
/1000; }
104 int nsec() const { return tv
.tv_nsec
; }
106 // ref accessors/modifiers
107 __u32
& sec_ref() { return tv
.tv_sec
; }
108 __u32
& nsec_ref() { return tv
.tv_nsec
; }
110 uint64_t to_nsec() const {
111 return (uint64_t)tv
.tv_nsec
+ (uint64_t)tv
.tv_sec
* 1000000000ull;
113 uint64_t to_msec() const {
114 return (uint64_t)tv
.tv_nsec
/ 1000000ull + (uint64_t)tv
.tv_sec
* 1000ull;
117 void copy_to_timeval(struct timeval
*v
) const {
118 v
->tv_sec
= tv
.tv_sec
;
119 v
->tv_usec
= tv
.tv_nsec
/1000;
121 void set_from_timeval(const struct timeval
*v
) {
122 tv
.tv_sec
= v
->tv_sec
;
123 tv
.tv_nsec
= v
->tv_usec
*1000;
125 void padding_check() {
131 "utime_t have padding");
133 void encode(bufferlist
&bl
) const {
134 #if defined(CEPH_LITTLE_ENDIAN)
135 bl
.append((char *)(this), sizeof(__u32
) + sizeof(__u32
));
138 encode(tv
.tv_sec
, bl
);
139 encode(tv
.tv_nsec
, bl
);
142 void decode(bufferlist::const_iterator
&p
) {
143 #if defined(CEPH_LITTLE_ENDIAN)
144 p
.copy(sizeof(__u32
) + sizeof(__u32
), (char *)(this));
147 decode(tv
.tv_sec
, p
);
148 decode(tv
.tv_nsec
, p
);
152 DENC(utime_t
, v
, p
) {
153 denc(v
.tv
.tv_sec
, p
);
154 denc(v
.tv
.tv_nsec
, p
);
158 void encode_timeval(struct ceph_timespec
*t
) const {
159 t
->tv_sec
= tv
.tv_sec
;
160 t
->tv_nsec
= tv
.tv_nsec
;
162 void decode_timeval(const struct ceph_timespec
*t
) {
163 tv
.tv_sec
= t
->tv_sec
;
164 tv
.tv_nsec
= t
->tv_nsec
;
167 utime_t
round_to_minute() {
170 localtime_r(&tt
, &bdt
);
173 return utime_t(tt
, 0);
176 utime_t
round_to_hour() {
179 localtime_r(&tt
, &bdt
);
183 return utime_t(tt
, 0);
186 utime_t
round_to_day() {
189 localtime_r(&tt
, &bdt
);
194 return utime_t(tt
, 0);
198 operator double() const {
199 return (double)sec() + ((double)nsec() / 1000000000.0L);
201 operator ceph_timespec() const {
211 nanosleep(&ts
, NULL
);
215 ostream
& gmtime(ostream
& out
) const {
216 out
.setf(std::ios::right
);
217 char oldfill
= out
.fill();
219 if (sec() < ((time_t)(60*60*24*365*10))) {
220 // raw seconds. this looks like a relative time.
221 out
<< (long)sec() << "." << std::setw(6) << usec();
223 // this looks like an absolute time.
224 // aim for http://en.wikipedia.org/wiki/ISO_8601
228 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
229 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
230 << '-' << std::setw(2) << bdt
.tm_mday
232 << std::setw(2) << bdt
.tm_hour
233 << ':' << std::setw(2) << bdt
.tm_min
234 << ':' << std::setw(2) << bdt
.tm_sec
;
235 out
<< "." << std::setw(6) << usec();
239 out
.unsetf(std::ios::right
);
244 ostream
& gmtime_nsec(ostream
& out
) const {
245 out
.setf(std::ios::right
);
246 char oldfill
= out
.fill();
248 if (sec() < ((time_t)(60*60*24*365*10))) {
249 // raw seconds. this looks like a relative time.
250 out
<< (long)sec() << "." << std::setw(6) << usec();
252 // this looks like an absolute time.
253 // aim for http://en.wikipedia.org/wiki/ISO_8601
257 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
258 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
259 << '-' << std::setw(2) << bdt
.tm_mday
261 << std::setw(2) << bdt
.tm_hour
262 << ':' << std::setw(2) << bdt
.tm_min
263 << ':' << std::setw(2) << bdt
.tm_sec
;
264 out
<< "." << std::setw(9) << nsec();
268 out
.unsetf(std::ios::right
);
273 ostream
& asctime(ostream
& out
) const {
274 out
.setf(std::ios::right
);
275 char oldfill
= out
.fill();
277 if (sec() < ((time_t)(60*60*24*365*10))) {
278 // raw seconds. this looks like a relative time.
279 out
<< (long)sec() << "." << std::setw(6) << usec();
281 // this looks like an absolute time.
282 // aim for http://en.wikipedia.org/wiki/ISO_8601
288 asctime_r(&bdt
, buf
);
289 int len
= strlen(buf
);
290 if (buf
[len
- 1] == '\n')
295 out
.unsetf(std::ios::right
);
299 ostream
& localtime(ostream
& out
) const {
300 out
.setf(std::ios::right
);
301 char oldfill
= out
.fill();
303 if (sec() < ((time_t)(60*60*24*365*10))) {
304 // raw seconds. this looks like a relative time.
305 out
<< (long)sec() << "." << std::setw(6) << usec();
307 // this looks like an absolute time.
308 // aim for http://en.wikipedia.org/wiki/ISO_8601
311 localtime_r(&tt
, &bdt
);
312 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
313 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
314 << '-' << std::setw(2) << bdt
.tm_mday
316 << std::setw(2) << bdt
.tm_hour
317 << ':' << std::setw(2) << bdt
.tm_min
318 << ':' << std::setw(2) << bdt
.tm_sec
;
319 out
<< "." << std::setw(6) << usec();
320 //out << '_' << bdt.tm_zone;
323 out
.unsetf(std::ios::right
);
327 int sprintf(char *out
, int outlen
) const {
330 localtime_r(&tt
, &bdt
);
332 return ::snprintf(out
, outlen
,
333 "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
334 bdt
.tm_year
+ 1900, bdt
.tm_mon
+ 1, bdt
.tm_mday
,
335 bdt
.tm_hour
, bdt
.tm_min
, bdt
.tm_sec
, usec());
338 static int snprintf(char *out
, int outlen
, time_t tt
) {
340 localtime_r(&tt
, &bdt
);
342 return ::snprintf(out
, outlen
,
343 "%04d-%02d-%02d %02d:%02d:%02d",
344 bdt
.tm_year
+ 1900, bdt
.tm_mon
+ 1, bdt
.tm_mday
,
345 bdt
.tm_hour
, bdt
.tm_min
, bdt
.tm_sec
);
348 static int invoke_date(const std::string
& date_str
, utime_t
*result
) {
351 SubProcess
bin_date("/bin/date", SubProcess::CLOSE
, SubProcess::PIPE
, SubProcess::KEEP
);
352 bin_date
.add_cmd_args("-d", date_str
.c_str(), "+%s %N", NULL
);
354 int r
= bin_date
.spawn();
357 ssize_t n
= safe_read(bin_date
.get_stdout(), buf
, sizeof(buf
));
360 if (r
|| n
<= 0) return -EINVAL
;
362 uint64_t epoch
, nsec
;
363 std::istringstream
iss(buf
);
368 *result
= utime_t(epoch
, nsec
);
374 static int parse_date(const string
& date
, uint64_t *epoch
, uint64_t *nsec
,
375 string
*out_date
=NULL
, string
*out_time
=NULL
) {
377 memset(&tm
, 0, sizeof(tm
));
382 const char *p
= strptime(date
.c_str(), "%Y-%m-%d", &tm
);
386 p
= strptime(p
, " %H:%M:%S", &tm
);
389 if (nsec
&& *p
== '.') {
392 char buf
[10]; /* 9 digit + null termination */
393 for (i
= 0; (i
< sizeof(buf
) - 1) && isdigit(*p
); ++i
, ++p
) {
396 for (; i
< sizeof(buf
) - 1; ++i
) {
401 *nsec
= (uint64_t)strict_strtol(buf
, 10, &err
);
409 int r
= sscanf(date
.c_str(), "%d.%d", &sec
, &usec
);
418 *nsec
= (uint64_t)usec
* 1000;
421 time_t t
= internal_timegm(&tm
);
423 *epoch
= (uint64_t)t
;
427 strftime(buf
, sizeof(buf
), "%F", &tm
);
432 strftime(buf
, sizeof(buf
), "%T", &tm
);
439 bool parse(const string
& s
) {
440 uint64_t epoch
, nsec
;
441 int r
= parse_date(s
, &epoch
, &nsec
);
445 *this = utime_t(epoch
, nsec
);
449 WRITE_CLASS_ENCODER(utime_t
)
450 WRITE_CLASS_DENC(utime_t
)
452 // arithmetic operators
453 inline utime_t
operator+(const utime_t
& l
, const utime_t
& r
) {
454 __u64 sec
= (__u64
)l
.sec() + r
.sec();
455 return utime_t(cap_to_u32_max(sec
), l
.nsec() + r
.nsec());
457 inline utime_t
& operator+=(utime_t
& l
, const utime_t
& r
) {
458 l
.sec_ref() = cap_to_u32_max((__u64
)l
.sec() + r
.sec());
459 l
.nsec_ref() += r
.nsec();
463 inline utime_t
& operator+=(utime_t
& l
, double f
) {
464 double fs
= trunc(f
);
465 double ns
= (f
- fs
) * 1000000000.0;
466 l
.sec_ref() = cap_to_u32_max(l
.sec() + (__u64
)fs
);
467 l
.nsec_ref() += (long)ns
;
472 inline utime_t
operator-(const utime_t
& l
, const utime_t
& r
) {
473 return utime_t( l
.sec() - r
.sec() - (l
.nsec()<r
.nsec() ? 1:0),
474 l
.nsec() - r
.nsec() + (l
.nsec()<r
.nsec() ? 1000000000:0) );
476 inline utime_t
& operator-=(utime_t
& l
, const utime_t
& r
) {
477 l
.sec_ref() -= r
.sec();
478 if (l
.nsec() >= r
.nsec())
479 l
.nsec_ref() -= r
.nsec();
481 l
.nsec_ref() += 1000000000L - r
.nsec();
486 inline utime_t
& operator-=(utime_t
& l
, double f
) {
487 double fs
= trunc(f
);
488 double ns
= (f
- fs
) * 1000000000.0;
489 l
.sec_ref() -= (long)fs
;
493 l
.nsec_ref() = 1000000000L + l
.nsec_ref() - nsl
;
501 inline bool operator>(const utime_t
& a
, const utime_t
& b
)
503 return (a
.sec() > b
.sec()) || (a
.sec() == b
.sec() && a
.nsec() > b
.nsec());
505 inline bool operator<=(const utime_t
& a
, const utime_t
& b
)
507 return !(operator>(a
, b
));
509 inline bool operator<(const utime_t
& a
, const utime_t
& b
)
511 return (a
.sec() < b
.sec()) || (a
.sec() == b
.sec() && a
.nsec() < b
.nsec());
513 inline bool operator>=(const utime_t
& a
, const utime_t
& b
)
515 return !(operator<(a
, b
));
518 inline bool operator==(const utime_t
& a
, const utime_t
& b
)
520 return a
.sec() == b
.sec() && a
.nsec() == b
.nsec();
522 inline bool operator!=(const utime_t
& a
, const utime_t
& b
)
524 return a
.sec() != b
.sec() || a
.nsec() != b
.nsec();
531 inline std::ostream
& operator<<(std::ostream
& out
, const utime_t
& t
)
533 return t
.localtime(out
);
536 inline std::string
utimespan_str(const utime_t
& age
) {
537 auto age_ts
= ceph::timespan(age
.nsec()) + std::chrono::seconds(age
.sec());
538 return timespan_str(age_ts
);