您现在可能已经意识到,无法添加日期。
日期和时间戳在数学上类似于tensors,因为它们的不同类型在不同的域中。
当您评论 time_duration 不包含日期时,您仍然有道理。
因为time_duration 可能是时域差异类型(差异类型ptime),但我们需要ptime 的日期部分的模拟,即boost::gregorian::date。
Boost Gregorian 日期基本上是 (yyyy,mm,dd) 的祝福元组。所以自然差异类型只是 有符号整数天数。这就是完全正确*boost::gregorian::date_duration 是什么:
boost::gregorian::date_duration x = date{} - date{};
boost::posix_time::time_duration y = ptime{} - ptime{};
因为该类型是在 Gregorian 模块中实现的,所以即使在闰日和其他异常等特殊情况下,您也会得到正确的差异:https://www.calendar.com/blog/gregorian-calendar-facts/
因此,您实际上可以将该类型用作差异类型,仅用于 ymd 部分。
简化
好消息是,您不必费心:boost::posix_time::ptime 封装了一个完整的 boost::gregorian::date,因此当您从 ptimes 中减去 boost::posix_time::time_duration 时,您将已经 获取加密天数:
#include <boost/date_time.hpp>
int main() {
auto now = boost::posix_time::microsec_clock::local_time();
auto later = now + boost::posix_time::hours(3);
auto tomorrow = later + boost::gregorian::days(1);
auto ereweek = later - boost::gregorian::weeks(1);
std::cout << later << " is " << (later - now) << " later than " << now
<< std::endl;
std::cout << tomorrow << " is " << (tomorrow - later) << " later than " << later
<< std::endl;
std::cout << ereweek << " is " << (ereweek - now) << " later than " << now
<< std::endl;
}
从当前时间开始,我们增加 3 小时 1 天,然后减去一周。它打印:Live On Coliru:
2021-Mar-28 01:50:45.095670 is 03:00:00 later than 2021-Mar-27 22:50:45.095670
2021-Mar-29 01:50:45.095670 is 24:00:00 later than 2021-Mar-28 01:50:45.095670
2021-Mar-21 01:50:45.095670 is -165:00:00 later than 2021-Mar-27 22:50:45.095670
请注意,24h 是 1 天,-165h 是 (7*24 - 3) 小时前。
公历模块中有很多智能:
std::cout << date{2021, 2, 1} - date{2020, 2, 1} << std::endl; // 366
std::cout << date{2020, 2, 1} - date{2019, 2, 1} << std::endl; // 365
考虑到闰日。但也要了解上下文中日历月的不同长度:
auto term = boost::gregorian::months(1);
for (date origin : {date{2021, 2, 17}, date{2021, 3, 17}}) {
std::cout << ((origin + term) - origin) << std::endl;
};
分别打印 28 和 31。
将其应用于您的类型
我建议保留库差异类型,因为显然您之前没有考虑过您需要它。通过简单地创建一些相互转换,您就可以拥有自己的蛋糕并吃掉它:
struct MyDateTime {
MyDateTime(int year = 1970, int month = 1, int day = 1, uint64_t nanos = 0)
: year(year),
month(month),
day(day),
nanosSinceMidnight(nanos) {}
operator ptime() const {
return {date(year, month, day),
microseconds(nanosSinceMidnight / 1'000)};
}
explicit MyDateTime(ptime const& from)
: year(from.date().year()),
month(from.date().month()),
day(from.date().day()),
nanosSinceMidnight(from.time_of_day().total_milliseconds() * 1'000) {}
private:
int year;
int month;
int day;
uint64_t nanosSinceMidnight;
};
现在,我会质疑保留 MyDateTime 类型的用处,但我意识到存在遗留代码,有时您需要更长的时间才能摆脱它。
纳秒
默认情况下不启用纳秒精度。你需要[选择使用它](https://www.boost.org/doc/libs/1_58_0/doc/html/date_time/details.html#boost-common-heading-doc-spacer:~:text=To%20use%20the%20alternate%20resolution%20(96,the%20variable%20BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG%20must%20be%20defined).
在下面的示例中,我这样做了。
注意项目中的所有翻译单元都使用定义,否则会导致ODR violations。
现场演示
添加一些方便operator<< 为好:
Live On Coliru
#define BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
#include <boost/date_time.hpp>
#include <vector>
using boost::posix_time::ptime;
using boost::gregorian::date;
using boost::posix_time::nanoseconds;
struct MyDateTime {
MyDateTime(MyDateTime const&) = default;
MyDateTime& operator=(MyDateTime const&) = default;
MyDateTime(int year = 1970, int month = 1, int day = 1, uint64_t nanos = 0)
: year(year),
month(month),
day(day),
nanosSinceMidnight(nanos) {}
operator ptime() const {
return {date(year, month, day), nanoseconds(nanosSinceMidnight)};
}
/*explicit*/ MyDateTime(ptime const& from)
: year(from.date().year()),
month(from.date().month()),
day(from.date().day()),
nanosSinceMidnight(from.time_of_day().total_nanoseconds()) {}
private:
friend std::ostream& operator<<(std::ostream& os, MyDateTime const& dt) {
auto save = os.rdstate();
os << std::dec << std::setfill('0') << std::setw(4) << dt.year << "/"
<< std::setw(2) << dt.month << "/" << std::setw(2) << dt.day << " +"
<< dt.nanosSinceMidnight;
os.setstate(save);
return os;
}
int year;
int month;
int day;
uint64_t nanosSinceMidnight;
};
int main() {
namespace g = boost::gregorian;
namespace p = boost::posix_time;
using p::time_duration;
std::vector<time_duration> terms{p::seconds(30), p::hours(-168),
p::minutes(-15),
p::nanoseconds(60'000'000'000 * 60 * 24)};
for (auto mydt : {MyDateTime{2021, 2, 17}, MyDateTime{2021, 3, 17}}) {
std::cout << "---- Origin: " << mydt << "\n";
for (time_duration term : terms) {
mydt = ptime(mydt) + term;
std::cout << "Result: " << mydt << "\n";
}
};
}
打印
---- Origin: 2021/02/17 +0
Result: 2021/02/17 +30000000000
Result: 2021/02/10 +30000000000
Result: 2021/02/09 +85530000000000
Result: 2021/02/10 +85530000000000
---- Origin: 2021/03/17 +0
Result: 2021/03/17 +30000000000
Result: 2021/03/10 +30000000000
Result: 2021/03/09 +85530000000000
Result: 2021/03/10 +85530000000000