在这里非常感谢 罗剑锋老师的《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_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); |
| date d5(boost::date_time::min_date_time); |
| } |
如果使用了不存在或者非法的日期则会抛出相应的异常
- 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); |
| d-=months(1); |
| d+=months(2); |
| 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); |
| 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)); |
| assert(dp.begin().day()==1); |
| assert(dp.begin().days()==26); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构