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

概述:

        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-31
	date 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-20
	cout<< "date d: "<< to_iso_string(d) << endl;//输出结果: date d: 20081120
	cout<< "date d: "<< to_iso_extended_string(d) <<endl;//输出结果:date d: 2008-11-20
	cout<< "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.days
	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) );//除法

	//输出时长
	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个月,结果可能不是同一天的日期
	//规律是:一旦日期在运算过程中变为月末,那么原来的天数信息就会丢失
	//----------------
	//例1
	date 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月的最后一天31

	cout<<"d6 + months(2): "<<to_iso_extended_string( d6 += months(2))<<endl;//与原始日期不同,是3月最后一天31
	//----------------
	//----------------
	//例2
	date 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月最后一天,与原始日期相同

	//----------------
	//例3
	date 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() );

	//合并两个区间及两者之间的间隔,广义的merge
	assert( 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值