由于我不能使用 C++20,我最终得到了这个基于 C++11 的最小 std::chrono 实现:
utctime.h
#include <chrono>
#include <string>
struct UTCClock
{
typedef std::chrono::microseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<UTCClock, duration> time_point;
static const bool is_steady = true;
//
// every time_point will be generated from here
//
static time_point fromDate(int year= 0, int month= 0, int day= 0,
int hour= 0, int min = 0, int sec= 0,
int usec= 0);
//
// convert time_point to a date/time representation
//
static void toDate(const time_point &tp,
int &year, int &month, int &day,
int &hour, int &min, int &sec,
int &usec);
// NOT Supported, we don't need current time. We only
// want to represent UTC DateTime
// static time_point now();
};
using UTCTime = std::chrono::time_point<UTCClock, std::chrono::microseconds>;
utctime.cpp
#include "utctime.h"
#include <ctime>
namespace chrono = std::chrono;
using chrono::duration_cast;
using chrono::time_point_cast;
namespace {
std::time_t to_time_t(const UTCClock::time_point &tp) noexcept
{
return std::time_t(
duration_cast<chrono::seconds>(tp.time_since_epoch()).count());
}
UTCClock::time_point from_time_t(std::time_t tt) noexcept
{
return time_point_cast<UTCClock::duration>(
chrono::time_point<UTCClock,chrono::seconds>(chrono::seconds(tt)));
}
} // namespace
UTCClock::time_point UTCClock::fromDate(
int year, int month, int day, int hour, int min, int sec, int usec)
{
std::tm tm = {0};
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = min;
tm.tm_sec = sec;
tm.tm_isdst = -1;
std::time_t tt = timegm(&tm);
return from_time_t(tt) + chrono::microseconds(usec);
}
void UTCClock::toDate(const UTCClock::time_point &tp,
int &year,
int &month,
int &day,
int &hour,
int &min,
int &sec,
int &usec)
{
std::time_t tt = to_time_t(tp);
std::tm tm;
gmtime_r(&tt, &tm);
year = tm.tm_year + 1900;
month = tm.tm_mon + 1;
day = tm.tm_mday;
hour = tm.tm_hour;
min = tm.tm_min;
chrono::microseconds leftover =
tp - from_time_t(tt) + chrono::seconds(tm.tm_sec);
sec = duration_cast<chrono::seconds>(leftover).count();
usec = (leftover-chrono::seconds(sec)).count();
}
可以这样使用:
#include "utctime.h"
#include <iostream>
using namespace std::chrono;
int main(int argc, char* argv[])
{
//
// use UTCClock::fromDate to generate a UTCTime
//
UTCTime t1 = UTCClock::fromDate(1901, 1, 1, 0, 0, 0, 0);
UTCTime t2 = UTCClock::fromDate(1901, 1, 1, 1, 0, 0, 0);
//
// Then we can make use of std::chrono algebra like
// subtracting time_point
//
microseconds timeDiff = t2 -t1;
std::cout << "t2-t1 difference in microseconds " <<
timeDiff.count() << std::endl;
std::cout << "t2-t1 difference in hours " <<
duration_cast<hours>(timeDiff).count() << std::endl;
//
// ...or adding/subtracting a duration to a time_point
//
UTCTime t3 = t1 - minutes{3};
std::cout << "t3-t1 difference in minutes " <<
duration_cast<minutes>(t3-t1).count() << std::endl;
t3 = t1 + milliseconds{123};
std::cout << "t3-t1 difference in milliseconds " <<
duration_cast<milliseconds>(t3-t1).count() << std::endl;
//
// ...we can also compare time_points
//
if ( t3 > t1 ) std::cout << "t3 is greater than t1" << std::endl;
//
// We can get a date/time back from a time_point with UTCClock::toDate
//
int year, month, day, hour, min, sec, usec;
UTCClock::toDate(t3, year, month, day, hour, min, sec, usec);
//
// std::chrono is also type safe and doesn't allow to
// mix dates generated by different clocks
//
system_clock::time_point systp = system_clock::now();
// NO: doesn't compile
// auto tx = t1 - systp;
// NO: doesn't compile
// if (t1 < systp);
// NO: doesn't compile
// UTCClock::toDate(systp, year, month, day, hour, min, sec, usec);
return 0;
}
输出:
t2-t1 difference in microseconds 3600000000
t2-t1 difference in hours 1
t3-t1 difference in minutes -3
t3-t1 difference in milliseconds 123
t3 is greater than t1