在这里非常感谢 罗剑锋老师的《Boost程序库完全开发指南》以下内容完全来自本书,在学习的过程中作为笔记使用。
这里给出debug的宏定义
#define debug(x) std::cout<<x<<std::endl;
1 安装
直接从官网下载
@TODO:后续附上下载链接
axel -n20 https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.bz2 sudo tar -jxvf boost_1_73_0.tar.bz2 cd boost_1_73_0/ sudo ./bootstrap.sh sudo ./b2 --buildtype=complete install
如果像上面这样不指定额外选项,Boost将编译release版本的库文件,把头文件安装到“/usr/local/include”中,把库文件安装到“/usr/local/lib”中
等待安装完成即可
cmake 配置
#set(BOOST_ROOT ~/boost_1_73_0) #这句话已经注释了 也可以指定boost的根目录 默认安装到/usr/local中之后 就不需要指定目录 set(Boost_NO_SYSTEM_PATHS ON) # 只搜索上语句设置的搜索路径 find_package(Boost COMPONENTS regex system REQUIRED) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) endif() add_executable(boost_test test.cpp )
下面就可以编写代码了
2 日期与时间操作
2.1 timer 库
timer对象一旦被声明,它的构造函数就会开始计时,后面直接使用elapsed()函数进行测量时间
boost::timer t; //声明一个计时器对象 debug("max timespan:"<<t.elapsed_max()/3600<<"h") // 最大的时间范围 debug("min timespan:"<<t.elapsed_min()<<"s") // 最小的时间范围 for(i=0;i<10000;i++); debug("now time elapsed:"<<t.elapsed()<<"s") //从声明对象到当前行已使用的时间 debug("timer end")
timer的计时使用的是标准库中里的std::clock()函数,timer的构造函数记录当前clock数作为起始点,每次调用的elapsed()就会获取当前clock 然后减去起始点得到当前流逝或消耗的时间。
美妙的clock数由宏CLOCKS_PER_SEC定义。
elapsed_min是CLOCKS_PER_SEC的倒数
elapsed_max使用的是标准库数值的极限类numberic_limits,获得clock_t类型的最大值
2.2 progress_timer
progress_timer派生自timer,会在析构的时候自动输出时间
#include <boost/progress.hpp> using namespace boost; progress_timer t; debug(t.elapsed())//输出当前流逝的时间 { progress_timer t1;//声明之后再析构的时候自动输出流逝的时间 for(i=0;i<10000;i++); }
progress_timer的类摘要
class progress_timer:public timer,noncopyable { public: explicit progress_timer(); progress_timer(std::ostream&os); ~progress_timer(); }
从上面的类摘要可以看出它允许析构的时候输出定向到指定的输入输出流里,默认是std::cout。
stringstream ss; { progress_timer t(ss); } debug(ss.str())
2.3 date_time库概述
日期和时间作为一种基础的设施广泛的用在很多地方。
date_time库基于我们日常使用的公历,可以提供与时间相关的各种所需功能,如精确的定义时间点,时间段,时间长度,加减若干天/月/年、日期迭代器等。还支持无限时间和无效时间等概念,可与c中的结构tm进行互相转换
2.3.1使用方式
- 处理日期gregorian
- 处理时间posix_time
//处理日期的组件 #include<boost/date_time/gregorian/gregorian.hpp> using namespace boost::gregorian; //处理时间的组件 #include<boost/date_time/posix_time/posix_time.hpp> using namespace boost::posix_time;
2.3.1 基本概念
- pos_infin:表示正无限
- neg_infin:表示负无限
- not_a_date_time:无效时间
- min_date_time:可表示的最小时间
- max_date_time:可表示的最大日期
2.4处理日期
date_time库是基于格里高利历,支持从1400-01-01到9999-12-31之间的日期计算
2.4.1 日期
date 是date_time 库处理日期的核心类。使用一个32位的整数作为内部存储,以天为单位表示时间概念,
template<typename T,typename calender,typename duration_type_> class date{ public: date(year_type,month_type,day_type); date(const ymd_type&); year_type year() const; month_type month()const; day_type day()const; day_of_week_type day_of_week()const; bool operate<(const date_type&)const; bool operate==(const date_type&)const; bool is_special() const; bool is_not_a_date()const; bool is_infinity()const; bool is_pos_infinity() const; bool is_neg_infinity()const; special_values as_special() const; duration_type operator-(const date_type&)const; ... };
date是一个轻量级对象,处理效率很高,所以可以拷贝传值,date也支持全面的比较操作和流输入输出操作。
{ using namespace boost::gregorian; boost::gregorian::date d1; boost::gregorian::date d2(2010,1,1); boost::gregorian::date d3(2010,Jan,2); date d4(d2); assert(d1 == date(not_a_date_time)); assert(d2 == d4); assert(d3>d4); } { using namespace boost::gregorian; date d1 = from_string("1996-06-22"); date d2(from_string("2022/1/1")); date d3 = from_undelimited_string("19960622"); cout<<day_clock::local_day()<<day_clock::universal_day<<endl; } { date d1(neg_infin); //负无限日期 date d2(pos_infin); //正无限日期 date d3(boost::date_time::not_a_date_time);//无效日期 date d4(max_date_time); //最大可能日期 9999-12-31 date d5(boost::date_time::min_date_time); //最小可能日期 1400-01-01 }
如果使用了不存在或者非法的日期则会抛出相应的异常
- boost::gregorian::bad_year
- boost::gregorian::bad_month
- boost::gregorian::bad_weekday
- boost::gregorian::bad_day_of_year
- boost::gregorian::bad_day_of_month
2.4.2 访问日期
{ using namespace boost::gregorian; //日期的访问 debug(date(2022,1,22).week_number()) debug(date(2022,1,3).week_number()) debug(date(2022,1,15).week_number()) debug(date(pos_infin).is_infinity()) debug(date(pos_infin).is_pos_infinity()) debug(date(neg_infin).is_neg_infinity()) debug(date(not_a_date_time).is_not_a_date()) debug(date(not_a_date_time).is_special()) debug(!date(2017,5,31).is_special()) }
2.4.3日期输出
date d(2022,1,25); debug(to_simple_string(d)) debug(to_iso_string(d)) debug(to_iso_extended_string(d)) debug(d) std::cin>>d; debug(d)
2.4.4与c结构的转换
{ using namespace boost::gregorian; date d(2022,1,25); tm t = to_tm(d); assert(t.tm_hour == 0 && t.tm_min==0); assert(t.tm_year == 122 && t.tm_mday ==25); date d2 = date_from_tm(t); assert(d == d2); }
2.4.5日期长度
日期的长度是以天为单位的时长,是度量时间长度的一个标量。基本日期长度类date_duration,下面是类摘要
class date_duration{ public: date_duration(long); //构造函数 date_duration(special_values); long days()const; //成员访问函数 bool is_special() const; bool is_negative() const; bool operator==(const date_duration&)const; ...... //其他操作符定义 static date_duration unit(); //时长单位 };
- date_duration(long) 创建一个日期长度
- days() 返回时长的天数,构造函数使用特殊值时,则返回特殊时长对象
- is_special() 判断对象是否是特殊值
- is_negative()是否为负值
- 支持全序比较操作(==、!=、< 、<=等)
- 支持加法、减法、递增、递减
- 支持除以一个整数,但不支持除以另外一个date_duration对象
- 不支持其他运算 如乘法 取模 取余
date_time库为date_duration定义了一个常用的typedef:days
{ using namespace boost::gregorian; days dd1(10),dd2(-100),dd3(255); assert(dd1>dd2 && dd1<dd3); assert(dd1+dd2 == days(-90)); assert((dd1+dd3).days()==265); assert(dd3/5==days(51)); }
为了方便计算时间长度,date_time库还提供了months、years、weeks3个时长类,分别用来表示月、年和星期,它们的含义与days类似,但其行为不太相同
months和 years全面支持加减乘除运算,使用成员函数 number_of_months()和number_of_years()可获得表示的月数和年数。weeks是date_duration的子类,除构造函数以7为单位以外,其他的行为与days完全相同,
{ using namespace boost::gregorian; weeks w(3); assert(w.days()==21); months m(5); years y(2); months m2 = y+m; assert(m2.number_of_months()==29); assert((y*2).number_of_years()==4); }
2.4.6 日期运算
{ using namespace boost::gregorian; date d1(2000,1,1),d2(2022,1,26); debug(d2-d1) assert(d1+(d2-d1) == d2); d1+=days(10); assert(d1.day()==11); d1+=months(2); assert(d1.month()==3 && d1.day()==11); d1 -= weeks(1); assert(d1.day()==4); d2 -=years(10); assert(d2.year()==d1.year()+11); } { using namespace boost::gregorian; date d1(2022,1,26); date d2 = d1+days(pos_infin); d2 = d1+days(not_a_date_time); assert(d2.is_not_a_date()); d2 = date(neg_infin); days dd = d1-d2; assert(dd.is_special()&&!dd.is_negative()); }
月末提醒
如果日期是月末最后一天,那么加减月或年会得到相同的月末时间,但是当天数是28或29时,如果加减月份到2月份,那么随后的运算就总是月末操作,原始的天数就会丢失
date d(2022,1,29); d+=months(1);//2022-2-28 d-=months(1);//2022-1-31 d+=months(2);//2022-3-31 assert(d.day()==31);
输出结果:
2022-Feb-28
2022-Jan-31
2022-Mar-31
2.4.7 日期区间
date_period 左闭右开,其端点是两个date对象。日期区间的左边界必须小于右边界,否则date_period将表示一个无效的日期区间。
类摘要
class date_period{ public: period( date, date); //构造函数 period( date, days); date begin() const; //区间端点操作 date end() const; date last() const; days length() const; bool is_null() const; bool operator==(const period& rhs) const; //比较操作 bool operator<(const period& rhs) const; void shift(const days& d); //平移 void expand(const days& d); //扩展 bool contains(const & point) const; //区间运算 bool contains(const period& other) const; bool intersects(const period& other) const; bool is_adjacent(const period& other) const; bool is_before(const & point) const; bool is_after(const & point) const; period intersection(const period& other) const; period merge(const period& other) const; period span(const period& other) const; };
日期区间的一些操作
{ using namespace boost::gregorian; date_period dp(date(2021,1,1),days(20)); assert(!dp.is_null()); assert(dp.begin().day() == 1); assert(dp.last().day() == 20); assert(dp.end().day() == 21);//返回last后的第一天 与标准容器中的end相同 assert(dp.length().days()==20); }
日期区间的比较操作使用的是区间的端点,即第一个区间的end() 和第二区间的begin(),判断这两个区间在时间轴上的位置大小
date_period dp1(date(2020,1,22),days(20)); date_period dp2(date(2020,2,22),days(20)); debugd(p1) assert(dp1<dp2);
2.4.8日期区间运算
成员函数shift()和expand()可以变动区间:shift()将日期区间平移n天而长度不变,expand()将日期区间向两端延伸n天,相当于区间长度增加2n天。
date_period dp(date(2022,1,26),days(20)); dp.shift(days(3));//整个区间平移三天 assert(dp.begin().day()==4); assert(dp.length().days() == 20); dp.expand(days(3));//向日期的两端平移3天 日期长度增加6天; assert(dp.begin().day()==1); assert(dp.begin().days()==26);