Boost练习1——时间和日期1

来源:互联网 发布:rf仿真软件 编辑:程序博客网 时间:2024/06/06 06:29

概述:

        Boost库 实现对时间和日期的处理,通过chrono、timer和data_timer库;

一、timer库

1、当前状态

        Boost1.48版以后的timer库由两个组件组成:早期的timer(V1)和新的cpu_timer(V2);

        早期的timer(V1),使用的是标准c/c++接口,因为计时精度不够等原因已经被声明为废弃(deprecated).

2、类介绍

(1)、timer类

 头文件:<boost/timert.hpp>

测量精度:Mac OS X、linux下的精度是微秒(0.000001s),Win32下的精度是毫秒(0.001s)。

使用建议:适用于大部分对精度要求不高的程序计时任务,不适合高精度的时间测量任务;

                     精度依赖操作系统或编译器,难以做到跨平台;

                    不适合大跨度时间段的测量,可提供的最大时间跨度为几百小时;

                    已被声明为废弃,未来有可能被移出Boost库;

例子:

//声明一个计时器对象,同时已经开始计时timer t;//可度量的最大时间,以小时为单位cout<< "max timespain:"<< t.elapsed_max() /3600 <<"h"<<endl;//可度量的最小时间,以秒为单位cout<<"min timespan :"<< t.elapsed_min() <<"s"<<endl;//输出从计时开始(对象被创建)到现在已经流逝的时间cout<<"now time elapsed:"<<t.elapsed()<< "s"<< endl;//重新计时,清零cout<<"clear timer"<<endl;t.restart();//再次输出已经流逝的时间cout<<"now time elapseed: "    <<t.elapsed() <<"s"<<endl;
结果:



(2)、progress_timer

头文件:<boost/progress.hpp>

测量精度:0.01s

使用建议:类似于timer,但是析构时自动输出流逝的时间,比timer方便,精度只有百分之一秒,不适合高精度计时

例子:

ostringstream oss1;oss1.clear();{   //声明progress_timer对象,并与输出流绑定   progress_timer t(oss1);   for(int i=0; i<10000; i++)   for(int x=0; x<10000; x++);}cout<<oss1.str().c_str()<<endl;
结果:


 (3)、扩展的progress_timer—new_progress_timer(非boost库类)

特点:类似progress_timer,但是可以输出任意精度的时间

头文件:new_progress_timer.h

代码如下:

//通过progress_timer扩展计时精度  //原则上程序库的代码不能被用户修改,不过我们可以通过模板技术仿造progress_timer编写一个新类  //new_progress_timer以实现任意精度的输出  #include <boost/progress.hpp>  #include <boost/static_assert.hpp> //静态断言,控制精度范围在0~10以内    template <int N = 2>   class new_progress_timer:public boost::timer{  public:      new_progress_timer(std::ostream& os = std::cout):m_os(os){          BOOST_STATIC_ASSERT(N >= 0 && N <= 10);      }      ~new_progress_timer()//析构函数是核心功能,保存IO流状态,然后设定输出精度,完成输出后恢复IO流的状态      {          try          {              //保存流的状态              std::istream::fmtflags old_flags = m_os.setf(std::istream::fixed,std::istream::floatfield);              std::streamsize old_prec = m_os.precision(N);              //输出时间              m_os << elapsed() << " s\n" << std::endl;              //恢复流状态              m_os.flags(old_flags);              m_os.precision(old_prec);          }          catch(...){}//析构函数绝不能抛出异常      }  private:      std::ostream &m_os;  };  //使用模板特例化,精度为2  //template<>  //class new_progress_timer<2>:public boost::progress_timer{};

例子:需包含上述头文件

ostringstream oss2;oss2.clear();{        new_progress_timer<10> t(oss2);for(int i=0; i<10000; ++i)for(int x=0; x<10000; ++x);new_progress_timer<2> t2(oss2);for(int j=0; j<10000; ++j)for(int y=0; y<10000; ++y);}cout<<oss2.str().c_str()<<endl;
结果:



(4)、progress_display

头文件:<boost/progress.hpp>

说明:虽然与progress_timer类共同位于progress.hpp中,但是progress_display是一个独立的类,与timer库中的其他组件——timer、progress_timer没有任何联系。

功能:在控制台上显示程序的执行进度

例子:

vector<string> v(100);char str[10];//填充向量for(vector<string>::size_type i=0; i<v.size(); ++i){sprintf(str, "%d", i);v[i] = string(str);}ofstream fs("./test.txt");//声明一个progress_display对象,基数是v的大小progress_display pd( v.size() );//开始迭代遍历向量,处理字符串,写入文件for(vector<string>::size_type i=0; i<v.size(); ++i){fs << v[i] <<endl;for(int j=0; j<10000; ++j)for(int x=0; x<1000; ++x);++pd;}

结果:


该类的缺点:当在进度输出过程中如果有其他输出,则该进度输出就会被打乱。一个不完美的解决方法:在每次显示进度时都调用restart()重新显示进度刻度,然后使用operator+=来指定当前进度,如:

pos++;

pd.restart( v.size() );

pd += pos;


二、date_time库

     date_time库是Boost中少数需要编译的库之一。

    (1)、 一种使用方法是:直接编译date_time库:

            b2 --with-date_time [--bulidtype=complete] [stdlib=stlport] [stage]

          参看:http://blog.csdn.net/zhanhuai1/article/details/7232995

    (2)、另一种更好的使用方法是:将data_time库的实现代码嵌入到工程中编译:

            在你的工程中添加如下.cpp文件:“dateprebuild.cpp”

//dateprebuild.cpp#include "stdafx.h"//一般都需要包含该头文件#define BOOST_DATE_TIME_SOURCE#include <libs/date_time/src/gregorian/greg_names.hpp>#include <libs/date_time/src/gregorian/date_generators.cpp>#include <libs/date_time/src/gregorian/greg_month.cpp>#include <libs/date_time/src/gregorian/greg_weekday.cpp>#include <libs/date_time/src/gregorian/gregorian_types.cpp>
             在使用date_time库的时候,需要在包含头文件之前定义宏BOOST_DATE_TIME_SOURCE、BOOST_DATE_TIME_NO_LIB 或者 BOOST_ALL_NO_LIB。例如下面的完整例子:

#include "stdafx.h"#define BOOST_DATE_TIME_SOURCE#include <boost/date_time/gregorian/gregorian.hpp>#include <iostream>using namespace std;using namespace boost::gregorian;int _tmain(int argc, _TCHAR* argv[]){date d(2010,1,1);cout<<d<<endl;return 0;}

1、日期处理

     日期只涉及 年、月、日。

     date_teim库的日期基于格里高利历(gregorian),支持从1400-01-01 到 9999-12-31之间的日期计算。位于名字空间boost::gregorian。

     使用时,除了上述的编译库,还要包含头文件:< boost/date_time/gregorian.hpp >即:

     #define BOOST_DATE_TIME_SOURCE

     #include <boost/date_time/gregorian/gregorian.hpp>

     using namespace boost::gregorian;

(1)、日期(即时间点)

    date类

    该类使用一个32位的整数作为内部存储,以天为单位表示时间点概念。

    是一个轻量级的对象,很小,处理效率很高,可以被拷贝传值,全面支持比较操作和流输入输出。

例子:

#include "stdafx.h"#define BOOST_DATE_TIME_SOURCE#include <boost/date_time/gregorian/gregorian.hpp>#include <iostream>using namespace std;using namespace boost::gregorian;int _tmain(int argc, _TCHAR* argv[]){//1.创建日期对象date d1;    //一个无效的日期date d2(2010,4,1);//使用数字构造日期date d3(2000, Jan, 1);//使用英文指定月份date d4(d2);//支持拷贝构造assert( d1 == date(not_a_date_time ));//比较一个临时对象assert( d2 == d4);//date支持比较操作assert( d3 < d4 );//2.创建特殊的日期date d5( neg_infin );//负无限日期date d6( pos_infin );//正有限日期date d7( not_a_date_time );//无效日期date d8( max_date_time );//最大可能日期 9999-12-31date d9( min_date_time );//最小可能日期 1400-01-01/*如果创建日期对象时使用非法的值,例如日期超出1400-01-01到9999-12-31的范围、使用不存在的月份或日期,那么 date_time库会抛出异常,可以使用what()获得具体的操作信息。例如:构造下面对象会抛出异常:date dX(1399,12,1); //超出日期下限date dY(10000, 1, 1);//超出日期上限date dZ(2010, 2, 29);//不存在的日期*///3.访问日期//3.1.成员函数year()、month()和day()分别返回日期的年、月、日assert( d2.year() == 2010 );assert( d2.month() == 4);assert( d2.day() == 1);//3.2.成员函数 year_month_day()返回一个date::ymd_type 结构,可以一次性地获取年月日数据:date::ymd_type ymd = d2.year_month_day();assert( ymd.year == 2010);assert( ymd.month == 4);assert( ymd.day == 1);//3.3.成员函数 day_of_week()返回date的星期数,0表示是星期天。// day_of_year()返回date是当年的第几天;// end_of_month()返回当月的最后一天的date对象// week_number()返回date所在周是当年的第几周,范围是0到53,如果年初的几天位于去年的周,那么// 周数为53,即第0周assert( date(2010,1,10).week_number() == 1);assert( date(2010,1,1).week_number() == 53);assert( date(2008,1,1).week_number() == 1);//3.4.五个成员函数:is_xxx()函数,用于检查日期是否是一个特殊日期assert( date(pos_infin).is_infinity() );//是否是一个无限日期assert( date(pos_infin).is_pos_infinity() );//是否是一个正无限日期assert( date(neg_infin).is_neg_infinity() );//是否是一个负无限日期assert( date(not_a_date_time).is_not_a_date() );//是否是一个无效日期assert( date(not_a_date_time).is_special() );//是否是一个特殊日期//4.日期的输出/**  to_simple_string( date d):转换为YYYY-mmm-DD格式的字符串,其中的mmm为3字符的英文月份名。*  to_iso_string( date d):转换为YYYYMMDD格式的数字字符串*  to_iso_extended_string( date d):转换为YYYY-MM-DD格式的数字字符串*  注:date也支持流输入输出,默认使用YYYY-mmm-DD格式*/date d( 2008,11,20);cout<< "date d: "<< to_simple_string(d) <<endl;//输出结果:date d: 2008-Nov-20cout<< "date d: "<< to_iso_string(d) << endl;//输出结果: date d: 20081120cout<< "date d: "<< to_iso_extended_string(d) <<endl;//输出结果:date d: 2008-11-20cout<< "date d: "<< d <<endl;//输出结果:date d: 2008-Nov-20//5.与tm结构的转换/**  to_tm(date):date转换到tm。tm的时分秒成员(tm_hour,tm_min, tm_sec)均置为0,夏令时标志tm_isdst置为-1(表示未知)。*  date_from_tm( tm datetm): tm转换到date.只使用年、月、日三个成员(tm_year、tm_mon、tm_mday),其他成员均被忽略。*/date da( 2010, 2,1);tm t = to_tm( da );assert( t.tm_hour == 0 && t.tm_min == 0 && t.tm_sec == 0);assert( t.tm_year == 110 && t.tm_mday == 1);date daa = date_from_tm( t );assert( daa == da );    //6.day_clock,是一个天级别的时钟,是一个工厂类,调用它的静态成员函数local_day()或universal_day()函数会返回一个当天的日期对象。cout<<"Current date: "<< day_clock::local_day() <<endl;cout<<"Current date: "<< day_clock::universal_day() <<endl;while(1);return 0;}
输出结果:



(2)、日期长度(data_duration)

   日期长度是以天为单位的时长,是度量时间长度的一个标量。它与日期不同,值可以是任意的整数,可负可正。

date_duration类

date_duration支持全序比较操作(==、!=、<、<=等),也支持完全的加减法和递增、递减操作,用起来像一个整数。还支持除法运算,可以除以一个整数,但不能除以另外一个date_duration,其他的数学运算如乘法、取模、取余则不支持。

      date_time库定义了常用的typedef类型,days、months、years,原型如下:

      typedef date_duration days;

typedef weeks_duration weeks;

typedef date_time::months_duration<greg_durations_config> months;

typedef date_time::years_duration<greg_durations_config> years;

可以undef宏BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES,使date_time库不包含它们的定义头文件<boost/date_time/date_duration_types.hpp>

注:使用days、months、years等,除了编译date_time库外,需要以下头部:

#define BOOST_DATE_TIME_SOURCE
#include <boost/date_time/gregorian/gregorian.hpp>

例子:

#include "stdafx.h"#define BOOST_DATE_TIME_SOURCE#include <boost/date_time/gregorian/gregorian.hpp>#include <iostream>using namespace std;using namespace boost::gregorian;int _tmain(int argc, _TCHAR* argv[]){//1.daysdays 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) );//除法//输出时长cout<<"dd1:"<<dd1<<"天"<<endl;cout<<"dd1:"<<dd1.days()<<"天"<<endl;//判断是否为特殊时长dd1.is_special() ? cout<<"dd1 is Special": cout<<"dd1 is't Special";cout<<endl;//判断是否为负时长dd1.is_negative() ? cout<<"dd1 is negative":cout<<"dd1 is't negative";cout<<endl;//返回单位时长,1天cout<<"单位时长: "<<days::unit()<<"天"<<endl;//2.months、years、weeks是另外的时长类,分别表示n个月、n年和n个星期weeks w( 3.1 );//3个星期months m( 5 );//5个月years y( 2 );//2年//输出时长cout<<"weeks w(3)时长: "<<w<<"天"<<endl;cout<<"weeks w(3)时长: "<<w.days()<<"天"<<endl;cout<<"months m(5)时长: "<<m.number_of_months()<<"月"<<endl;//注意因为每个月的天数不同,因此可以确定几个月但不能确定有多少天                            //,可以输出月数,而不能输出天数。cout<<"years y(2)时长: "<<y.number_of_years()<<"年"<<endl;//同上,years只能输出有几年,几个月(此函数返回值*12),但不能输出有多少天cout<<"2*y时长: "<<(y*2).number_of_years()<<"年"<<endl;months m2 = y + m; //2年零5个月cout<<"y+m时长: "<<m2.number_of_months()<<"月"<<endl;while(1);return 0;}

(3)、日期运算(date与时长概念配合运算)

date支持加减运算,两个date对象的加减操作是无意义的(date_time库会以编译错误的方式通知我们);

单独使用date_duration是不能确定精确的时长(比如有多少天),只有与date运算后,才可以实现。

date d1(2000, 1, 1), d2(2008, 8, 8);cout<<"d1 : "<<to_iso_extended_string(d1)<<endl;cout<<"d2 : "<<to_iso_extended_string(d2)<<endl;//1.输出两个日期的差,即时长cout<<"d2-d1 : "<< d2-d1<<endl;//一个日期加上时长等于另一个日期assert( d1 + (d2-d1) == d2);d1 +=days(10);cout<<"d1 +=days(10) : "<<to_iso_extended_string(d1)<<endl;d1 += months(2);cout<<"d1 += months(2) "<<to_iso_extended_string(d1)<<endl;d1 -= weeks(1);cout<<"d1 -= weeks(1) "<<to_iso_extended_string(d1)<<endl;d1 -= years(7);cout<<"d1 -= years(7) "<<to_iso_extended_string(d1)<<endl;//2.日期与特殊日期长度、特殊日期与日期长度的运算,结果是特殊日期date d3( 2014, 12, 30);date d4 = d3 + days( pos_infin );cout<< "d4: "<<to_iso_extended_string( d4 )<<endl;date d5 = date( neg_infin );days dd = d5 - d3;cout<<"d5 - d3:"<<dd <<endl;cout<<"d5 - d3:"<<dd.days()<<endl;//注意结果是一个极大的负数//3.注意如果日期是月末,那么该日期减去n个月再加上n个月,结果可能不是同一天的日期//规律是:一旦日期在运算过程中变为月末,那么原来的天数信息就会丢失//----------------//例1date d6(2010, 3, 30);//不是3月的最后一天cout<<"d6: "<<to_iso_extended_string( d6 )<<endl;cout<<"d6 - months(1): "<<to_iso_extended_string( d6 -= months(1))<<endl;//是2月的最后一天,先前的30丢失cout<<"d6 - months(1): "<<to_iso_extended_string( d6 -= months(1))<<endl;//是1月的最后一天31cout<<"d6 + months(2): "<<to_iso_extended_string( d6 += months(2))<<endl;//与原始日期不同,是3月最后一天31//----------------//----------------//例2date d7(2010, 3, 30);cout<<"d7: "<<to_iso_extended_string( d7 )<<endl;//不是3月最后一天cout<<"d7 - months(2): "<<to_iso_extended_string( d7 -= months(2))<<endl;//不是1月最后一天,先前的30未丢失cout<<"d7 + months(2): "<<to_iso_extended_string( d7 += months(2))<<endl;//不是3月最后一天,与原始日期相同//----------------//例3date d8(2010, 3, 30);cout<<"d8: "<<to_iso_extended_string( d8 )<<endl;//不是3月最后一天cout<<"d8 - months(2): "<<to_iso_extended_string( d8 -= months(2))<<endl;//不是1月最后一天,先前的30未丢失cout<<"d8 + months(1): "<<to_iso_extended_string( d8 += months(1))<<endl;//是2月最后一天,先前的30丢失cout<<"d8 + months(1): "<<to_iso_extended_string( d8 += months(1))<<endl;//是3月最后一天31,与原始日期不同//----------------
结果:

(4)、日期区间

date_period类表示日期区间,是一个左闭右开区间,端点是两个date对象,区间左值必须小于右值。否则表示一个无效日期区间。

注意:如果使用的嵌入源码的方式,而不是链接lib库,那么一定要在源代码中加入宏:

         #define BOOST_DATE_TIME_NO_LIB 或#define BOOST_DATE_TIME_SOURCE 

        否则,会在编译时报库的链接错误。

例子:

//1.创建 date_period 对象date_period  dp1( date(2010,1,1), days(20));date_period dp2( date(2010, 1, 21), date(2015,1,1) );//2.输出 :[YYYY-mmm-DD/YYYY-mmm-DD]cout<<dp1<<endl;cout<<dp2<<endl;    cout<<"dp2 begin: "<<dp2.begin()<<endl;cout<<"dp2 last:" <<dp2.last() <<endl;cout<<"dp2 end:"<<dp2.end()<<endl;//3.比较:date_period可以进行全序比较运算,依据区间端点而不是区间长度,//第一个区间的end()与第二个区间的begin()比较,判断两个区间在时间轴上位置的大小//如果两个日期区间相交或包含,那么比较操作无意义,断言会失败//注:如果前一个区间的end() 是后一区间的begin(),与相交或包含情况相同assert(dp1 < dp2 );
结果:



(5)、日期区间运算

例子:

date_period dp(date(2010, 1,1), days(20) );cout<<"org"<<dp<<endl;//shift()将日期区间平移n天而长度不变dp.shift( days(3) );cout<<"shift: "<<dp<<endl;//expand()将日期区间向两端延伸n天,相当于区间长度加2n天dp.expand( days(3) );cout<<"expand:"<< dp<<endl;//判断日期区间是否在日期前或后assert( dp.is_before( date(2010,2,1) ));assert( dp.is_after( date(2009, 12,1)) );//判断日期区间是否包含另一个区间date_period dp1( date(2010, 1, 1), days(10) );date_period dp2( date(2010, 1, 21), days(5) );assert( dp.contains( dp1 ));//判断两个日期区间是否存在交集assert( dp.intersects(dp1) );//返回两个区间的交集,如果无交集返回一个无效区间assert( dp.intersection( dp1 ) == dp1 );assert( dp1.intersection( dp2 ).is_null() );//判断两个区间是否相邻assert( !dp1.is_adjacent(dp2) );//返回两个区间的并集assert( dp.merge( dp1) == dp );assert( dp1.merge( dp2).is_null() );//合并两个区间及两者之间的间隔,广义的mergeassert( dp1.span( dp2).end() == dp2.end() );

结果:

(6)、日期迭代器

日期迭代器包括:day_iterator、week_iterator 、month_iterator和year_iterator。

注意:构造时要传入起始日期和增减步长(默认为1个单位);

          迭代器相当于一个date对象的指针;

          出于效率考虑,日期迭代器只提供前置的++、--操作符,不提供后置式;

          日期迭代器可以不用解引用操作符,就可以直接和其他日期对象比较大小;

          日期迭代器不符合标准迭代器的定义,没有difference_type、pointer、reference等内部类型定义,不能使用std::advance()或者operator+=来前进或者后退。

例子:

date d( 2015,1,1);cout<<"d: "<< d <<endl;//构造迭代器day_iterator d_iter( d );//增减步长为1天++d_iter;cout<<"迭代器加1:"<<*d_iter <<endl;assert( d_iter == date( 2015, 1, 2) );year_iterator y_iter( *d_iter, 3);//增减步长为3年cout<<"*y_iter为: "<< *y_iter <<endl;++y_iter;cout<<"迭代器加1:"<< *y_iter <<endl;//y_iter += 5;//error, 编译失败//std::advance( y_iter, 5);//error, 编译失败

结果:


(7)、其他功能:

 boost::gregorian::gregorian_calendar,基本上被date类在内部使用,用户很少使用,但它提供几个有用的静态函数:is_leap_year()可以判断年份是否是闰年,end_of_month_day()给定年份和月份后返回该月的最后一天等。

  此外,date_time库还提供了很多有用的日期生成器。


0 0
原创粉丝点击