2016-05-10 05:30:13 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
#include <ctime>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <ostream>
|
|
|
|
|
2016-08-02 05:14:09 +08:00
|
|
|
#include <fmt/format.h>
|
2016-05-10 05:30:13 +08:00
|
|
|
|
|
|
|
#include "utils/datetime/datetime_error.hpp"
|
|
|
|
#include "utils/total_ordering.hpp"
|
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
class Timestamp : public TotalOrdering<Timestamp> {
|
|
|
|
public:
|
|
|
|
Timestamp() : Timestamp(0, 0) {}
|
|
|
|
|
2017-11-23 23:36:54 +08:00
|
|
|
Timestamp(std::time_t time, long nsec = 0) : unix_time(time), nsec(nsec) {
|
2017-02-18 18:54:37 +08:00
|
|
|
auto result = gmtime_r(&time, &this->time);
|
|
|
|
|
|
|
|
if (result == nullptr)
|
|
|
|
throw DatetimeError("Unable to construct from {}", time);
|
|
|
|
}
|
|
|
|
|
|
|
|
Timestamp(const Timestamp&) = default;
|
|
|
|
Timestamp(Timestamp&&) = default;
|
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
static Timestamp Now() {
|
2017-02-18 18:54:37 +08:00
|
|
|
timespec time;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &time);
|
|
|
|
|
|
|
|
return {time.tv_sec, time.tv_nsec};
|
|
|
|
}
|
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
auto SecSinceTheEpoch() const { return unix_time; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
auto NanoSec() const { return nsec; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Year() const { return time.tm_year + 1900; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Month() const { return time.tm_mon + 1; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Day() const { return time.tm_mday; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Hour() const { return time.tm_hour; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Min() const { return time.tm_min; }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
long Sec() const { return time.tm_sec; }
|
|
|
|
|
|
|
|
long Subsec() const { return nsec / 10000; }
|
|
|
|
|
|
|
|
const std::string ToIso8601() const {
|
|
|
|
return fmt::format(fiso8601, Year(), Month(), Day(), Hour(), Min(), Sec(),
|
|
|
|
Subsec());
|
2017-02-18 18:54:37 +08:00
|
|
|
}
|
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
const std::string ToString(const std::string& format = fiso8601) const {
|
|
|
|
return fmt::format(format, Year(), Month(), Day(), Hour(), Min(), Sec(),
|
|
|
|
Subsec());
|
2017-05-17 16:08:57 +08:00
|
|
|
}
|
|
|
|
|
2017-02-18 18:54:37 +08:00
|
|
|
friend std::ostream& operator<<(std::ostream& stream, const Timestamp& ts) {
|
2018-02-02 18:11:06 +08:00
|
|
|
return stream << ts.ToIso8601();
|
2017-02-18 18:54:37 +08:00
|
|
|
}
|
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
operator std::string() const { return ToString(); }
|
2017-02-18 18:54:37 +08:00
|
|
|
|
|
|
|
constexpr friend bool operator==(const Timestamp& a, const Timestamp& b) {
|
|
|
|
return a.unix_time == b.unix_time && a.nsec == b.nsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr friend bool operator<(const Timestamp& a, const Timestamp& b) {
|
|
|
|
return a.unix_time < b.unix_time ||
|
|
|
|
(a.unix_time == b.unix_time && a.nsec < b.nsec);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::tm time;
|
|
|
|
|
2018-02-02 18:11:06 +08:00
|
|
|
/** http://en.cppreference.com/w/cpp/chrono/c/time_t */
|
2017-02-18 18:54:37 +08:00
|
|
|
std::time_t unix_time;
|
|
|
|
long nsec;
|
|
|
|
|
|
|
|
static constexpr auto fiso8601 =
|
|
|
|
"{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.{:05d}Z";
|
2016-05-10 05:30:13 +08:00
|
|
|
};
|