c++11 boost - date_time库 - 日期

2018-07-10 14:00:35

date 是 date_time 库处理日期的核心类,以天为单位表示时间点概念。

创建日期对象

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

using namespace boost::gregorian;
date d1;  //无效日期
date d2(2002,Jan,10);
date d3(2010,2,2);
date d4(d);

//从字符串中来创建
std::string ds("2002/1/25");
date d(from_string(ds));

date d(from_string("2018-07-10"));

std::string ds("20020125");
date d(from_undelimited_string(ds));
date d1(neg_infin);      //负无限日期
date d2(pos_infin); //正无限日期
date d3(not_a_date_time);   //无效日期 - date d3;
date d4(max_date_time);   //最大可能日期 9999-12-31
date d5(min_date_time);   //最小可能日期 1400-01-01
//键入不存在的日期会抛出异常
date d1(1399,12,1);
date d2(10000,1,1);
date d3(2017,2,29);

访问日期

d.year();
d.month();
d.day();

//如果要用到年月日,小面更效率
date d(2002,Jan,10);
date::ymd_type ymd = d.year_month_day();
// ymd.year  --> 2002, 
// ymd.month --> 1, 
// ymd.day   --> 10

d.day_of_week();  //Sunday,Monday...
d.day_of_year();  //1-366

d.end_of_month();  //返回最后一个月date对象
date d(pos_infin); 
d.is_infinity(); // --> true

date d(neg_infin);
d.is_neg_infinity(); // --> true

date d(neg_infin); 
d.is_pos_infinity(); // --> true

date d(not_a_date_time);
d.is_not_a_date(); // --> true

date d(pos_infin); 
date d2(not_a_date_time); 
date d3(2005,Mar,1);
d.is_special(); // --> true
d2.is_special(); // --> true
d3.is_special(); // --> false

日期输出

//"2002-Jan-01"
std::string to_simple_string(date d);

//"20020131"
std::string to_iso_string(date d);

//"2002-01-31"
std::string to_iso_extended_string(date d);

将 date 对象与 struct tm 互转

date d(2005,Jan,1);
tm d_tm = to_tm(d);
/* tm_year => 105
   tm_mon  => 0
   tm_mday => 1
   tm_wday => 6 (Saturday)
   tm_yday => 0
   tm_hour => 0
   tm_min  => 0
   tm_sec  => 0
   tm_isddst => -1 */

tm d_tm;
d_tm.tm_year = 105;
d_tm.tm_mon  = 0;
d_tm.tm_mday = 1;
date d = date_from_tm(d_tm);
// d => 2005-Jan-01


date_duration 可以创建以天为单位的时长。

date_duration dd(3);
dd.days() --> 3;

date_duration dd(-1); dd.is_negative();--> true

//返回最小单位
date_duration::unit() --> date_duration(1)

//相加相减
date_duration dd1(3);
date_duration dd2(5);
date_duration dd3 = dd1 + dd2;
date_duration dd4 = dd1 - dd2;

其他三个时长类

months m(2);
years y(1);
weeks w(1);

w.days;  //7

日期运算,如果加减的是特殊日期,则返回结果也是特殊日期。

date d1(2018,1,1);
date d2(2017,2,2);

d1 += days(10);  //+10天
d2 += years(2);  //加两年

利用 months,years这两个时长要注意,使用days则不会出现如下情况。

date d(2017,3,30);

d -= months(1);  //2017-2-28,变为月末
d -= months(1);  //2017-1-31
d += months(2);  //2017-3-31


date_period 类表示日期区间的概念。

date_period dp(date(2002,Jan,10),date(2002,Jan,12));
date_period dp(date(2002,Jan,10),days(2));
date_period dp1(dp);  //拷贝构造
//两端相加,天数不变
date_period dp(date(2005,Jan,1), days(3));
dp.shift(days(3)); 
// dp == 2005-Jan-04 to 2005-Jan-07

//向两端延伸
date_period dp(date(2005,Jan,2), days(2));
dp.expand(days(1));   //增加2天
// dp == 2005-Jan-01 to 2005-Jan-05

dp.expand(days(-1));  //减少2天
date_period dp(date(2002,Jan,1),date(2002,Jan,10));
dp.begin(); //2002-Jan-01
dp.last();  //2002-Jan-09

dp.end();    //2002-Jan-10
dp.length(); //9

//前面大于后面
date_period dp(date(2002,Jan,10),date(2002,Jan,1));
dp.is_null();  //true

//包含date
date d(2002,Jan,1);
date_period dp(d, date(2002,Jan,10));
dp.contains(date(2002,Jan,2));// true
date_period dp2(d, d);
dp.contains(date(2002,Jan,1));// false

//包含date_period
date_period dp1(date(2002,Jan,1),date(2002,Jan,10));
date_period dp2(date(2002,Jan,2),date(2002,Jan,3));
dp1.contains(dp2) --> true
dp2.contains(dp1) --> false

//是否有交集
date_period dp1(date(2002,Jan,1),date(2002,Jan,10));
date_period dp2(date(2002,Jan,2),date(2002,Jan,3));
dp2.intersects(dp1) --> true

//有交集就返回交集,无交集返回一个无效区间
date_period dp1(date(2002,Jan,1),date(2002,Jan,10));
date_period dp2(date(2002,Jan,2),date(2002,Jan,3));
dp2.intersection(dp1);  //dp2

//是否相邻
date_period dp1(date(2002,Jan,1),date(2002,Jan,3));
date_period dp2(date(2002,Jan,3),date(2002,Jan,10));
dp2.is_adjacent(dp1);  //true

date_period dp1(date(2002,Jan,10),date(2002,Jan,30));
date d(2002,Jan,3);
dp1.is_after(d);  //true

date_period dp1(date(2002,Jan,1),date(2002,Jan,3));
date d(2002,Jan,10);
dp1.is_before(d);  //true

//合并,无交集返回NULL
date_period dp1(date(2002,Jan,1),date(2002,Jan,10));
date_period dp2(date(2002,Jan,9),date(2002,Jan,31));
dp2.merge(dp1)
// 2002-Jan-01/2002-Jan-31

//扩展
date_period dp1(date(2002,Jan,1),date(2002,Jan,5));
date_period dp2(date(2002,Jan,9),date(2002,Jan,31));
dp2.span(dp1); // 2002-Jan-01/2002-Jan-31

日期迭代器,可以直接用 * 解引用,也可以直接 -> 来访问成员函数。因为重载了比较运算符,所以不解引用也可以比较。

day_iterator day_itr(date(2005,Jan,1));
++d_itr; // 2005-Jan-02
day_iterator 2day_itr(date(2005,Feb,1),2);
++2d_itr; // 2005-Feb-03

week_iterator wk_itr(date(2005,Jan,1));
++wk_itr; // 2005-Jan-08
week_iterator 2wk_itr(date(2005,Jan,1),2);
++2wk_itr; // 2005-Feb-15

month_iterator m_itr(date(2005,Jan,1));
++m_itr; // 2005-Feb-01
month_iterator 2m_itr(date(2005,Feb,1),2);
++2m_itr; // 2005-Apr-01

year_iterator y_itr(date(2005,Jan,1));
++y_itr; // 2006-Jan-01
year_iterator 2y_itr(date(2005,Feb,1),2);
++2y_itr; // 2007-Feb-01


例子

这里需要引入 boost_date_time.so 动态库,我安装的boost动态库目录为 /usr/local/lib/boost_1_65_1,然后在 /etc/ld.so.conf.d/boost.conf 里加上 /usr/local/lib/boost_1_65_1。要不然会报错如下

...
error: ld returned 1 exit status
cannot find -lboost_date_time
// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
#include <vector>
using namespace std;

//#define DATE_TIME_NO_DEFAULT_CONSTRUCTOR
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;

//////////////////////////////////////////

void case1()
{
    date d1;
    date d2(2010,1,1);
    date d3(2000, Jan , 1);
    date d4(d2);

    assert(d1 == date(not_a_date_time));
    assert(d2 == d4);
    assert(d3 <  d4);
}

//////////////////////////////////////////

void case2()
{
    date d1 = from_string("1999-12-31");
    date d2 ( from_string("2015/1/1") );
    date d3 = from_undelimited_string("20011118") ;

    cout << d1 << d2 << d3 << endl;

    cout << day_clock::local_day()    << endl;
    cout << day_clock::universal_day() << endl;

}

//////////////////////////////////////////
void case3()
{
    date d1(neg_infin);
    date d2(pos_infin);
    date d3(not_a_date_time);
    date d4(max_date_time);
    date d5(min_date_time);

    cout << d1 << d2 << d3 << d4 << d5 << endl;

    try
    {
        //date d1(1399,12,1);
        //date d2(10000,1,1);
        date d3(2017,2,29);
    }
    catch(std::exception& e)
    {
        cout << e.what() << endl;
    }
}

//////////////////////////////////////////
void case4()
{
    date d(2017,6,1);
    assert(d.year()  == 2017);
    assert(d.month() == 6);
    assert(d.day()   == 1);

    date::ymd_type ymd =  d.year_month_day();
    assert(ymd.year    == 2017);
    assert(ymd.month   == 6);
    assert(ymd.day     == 1);

    cout << d.day_of_week() << endl;
    cout << d.day_of_year() << endl;
    assert(d.end_of_month() == date(2017,6,30));

    cout << date(2015,1,10).week_number() << endl;
    cout << date(2016,1,10).week_number()  << endl;
    cout << date(2017,1,10).week_number()  << endl;

    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() );
    assert(!date(2017,5,31).is_special() );


}

//////////////////////////////////////////
void case5()
{
    date d(2017,1,23);

    cout << to_simple_string(d) << endl;
    cout << to_iso_string(d) << endl;
    cout << to_iso_extended_string(d) << endl;
    cout << d << endl;

    //cout << "input date:";
    //cin >>d;
    //cout << d;

}

//////////////////////////////////////////
void case6()
{
    date d(2017,5,20);
    tm t = to_tm(d);
    assert(t.tm_hour == 0 && t.tm_min == 0);
    assert(t.tm_year == 117 && t.tm_mday == 20);

    date d2 = date_from_tm(t);
    assert(d == d2);

}

//////////////////////////////////////////
void case7()
{
    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));

    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);

}

//////////////////////////////////////////
void case8()
{
    date d1(2000,1,1),d2(2017,11,18);
    cout << d2 - d1 << endl;
    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() + 7);

    {
        date d1(2017,1,1);

        date d2 = d1 + days(pos_infin);
        assert(d2.is_pos_infinity());

        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());
    }

    {
        date d(2017,3,30);
        d -= months(1);
        d -= months(1);
        d += months(2);
        assert(d.day() == 31);
    }
}

//////////////////////////////////////////
void case9()
{
    date_period dp1(date(2017,1,1), days(20));
    date_period dp2(date(2017,1,1), date(2016,1,1));
    date_period dp3(date(2017,3,1), days(-20));

    date_period dp(date(2017,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);

    {
        date_period dp1(date(2017,1,1), days(20));
        date_period dp2(date(2017,2,19), days(10));

        cout << dp1;                        //[2010-Jan-01/2010-Jan-20]
        assert(dp1 < dp2);
    }
}

//////////////////////////////////////////

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
    case8();
    case9();
}
[root@192 c++]# echo '/usr/local/lib/boost_1_65_1' > /etc/ld.so.conf.d/boost.conf 
[root@192 c++]# ldconfig
[root@192 c++]# g++ -std=c++11 -lboost_date_time -L /usr/local/lib/boost_1_65_1/ main.cpp 
[root@192 c++]# ./a.out 
1999-Dec-312015-Jan-012001-Nov-18
2018-Jul-10
2018-Jul-10
-infinity+infinitynot-a-date-time9999-Dec-311400-Jan-01
Day of month is not valid for year
Thu
152
2
1
2
2017-Jan-23
20170123
2017-01-23
2017-Jan-23
6531
// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
#include <vector>
using namespace std;

#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;

//////////////////////////////////////////
void case1()
{
    date_period dp(date(2017,1,1), 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.length().days() == 26);

}

//////////////////////////////////////////

void case2()
{
    date_period dp(date(2010,1,1), days(20));

    assert(dp.is_after(date(2009,12,1)));
    assert(dp.is_before(date(2010,2,1)));
    assert(dp.contains(date(2010,1,10)));

    date_period dp2(date(2010,1,5), days(10));
    assert(dp.contains(dp2));

    assert(dp.intersects(dp2));
    assert(dp.intersection(dp2) == dp2);

    date_period dp3(date(2010,1,21), days(5));
    assert(!dp3.intersects(dp2));
    assert(dp3.intersection(dp2).is_null());

    assert(dp.is_adjacent(dp3));
    assert(!dp.intersects(dp3));

}

//////////////////////////////////////////
void case3()
{
    date_period dp1(date(2010,1,1), days(20));
    date_period dp2(date(2010,1,5), days(10));
    date_period dp3(date(2010,2,1), days(5));
    date_period dp4(date(2010,1,15), days(10));

    assert( dp1.contains(dp2) && dp1.merge(dp2) == dp1);
    assert(!dp1.intersects(dp3) && dp1.merge(dp3).is_null());
    assert( dp1.intersects(dp2) && dp1.merge(dp4).end() == dp4.end());
    assert( dp1.span(dp3).end() == dp3.end());
}

//////////////////////////////////////////
void case4()
{
    date d(2007,9,28);
    day_iterator d_iter(d);

    assert(d_iter == d);
    ++d_iter;
    assert(d_iter == date(2007,9,29));

    year_iterator y_iter(*d_iter, 10);
    assert(y_iter == d + days(1));
    ++y_iter;
    assert(y_iter->year() == 2017);

    day_iterator iter(day_clock::local_day());
    ++iter;

    //iter += 5;
    //std::advance(iter, 5);
}

//////////////////////////////////////////
void case5()
{
    typedef gregorian_calendar gre_cal;
    cout << "Y2017 is "
        << (gre_cal::is_leap_year(2017)?"":"not")
        << " a leap year." << endl;
    assert(gre_cal::end_of_month_day(2017, 2) == 28);
}

//////////////////////////////////////////
void case6()
{
    date d(2017,1,23);

    date d_start(d.year(), d.month(), 1);
    date d_end = d.end_of_month();

    for(day_iterator d_iter(d_start);
        d_iter <= d_end; ++d_iter)
    {
            cout << *d_iter << " " <<
                    d_iter->day_of_week()<< endl;
    }

}

//////////////////////////////////////////
void case7()
{
    date d(2017,1,23);

    date d18years = d + years(18);
    cout << d18years << " is "
        << d18years.day_of_week()<< endl;

    int count = 0;
    for (day_iterator d_iter(date(d18years.year(),1,1));
            d_iter <= d18years.end_of_month(); ++d_iter)
    {
        if (d_iter->day_of_week() == Sunday)
        {
            ++count;
        }
    }
    cout << "total " << count << " Sundays." << endl;

    count = 0;
    for (month_iterator m_iter(date(d18years.year(),1,1));
            m_iter < date(d18years.year() + 1 ,1, 1); ++m_iter)
    {
        count += m_iter->end_of_month().day();
    }
    cout << "total " << count << " days of year." << endl;

}

//////////////////////////////////////////
class credit_card
{
public:
    string bank_name;
    int bill_day_no;

    credit_card(const char* bname, int no):
        bank_name(bname), bill_day_no(no){}

    int calc_free_days(date consume_day = day_clock::local_day()) const
    {
        date bill_day(consume_day.year(), consume_day.month(), bill_day_no);
        if (consume_day > bill_day)
        {
            bill_day += months(1);
        }

        return (bill_day - consume_day).days() + 20;
    }

    friend bool operator<(const credit_card& l, const credit_card& r)
    {

        return l.calc_free_days() < r.calc_free_days();
    }
};

void case8()
{
    credit_card a("A bank", 25);
    credit_card b("B bank", 12);

    credit_card tmp = std::max(a, b);
    cout << "You should use " << tmp.bank_name 
        << ", free days = " << tmp.calc_free_days() << endl;
}



//////////////////////////////////////////

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
    case8();
}
[root@192 c++]# g++ -std=c++11 -lboost_date_time -L /usr/local/lib/boost_1_65_1/ main.cpp 
[root@192 c++]# 
[root@192 c++]# ./a.out 
Y2017 is not a leap year.
2017-Jan-01 Sun
2017-Jan-02 Mon
2017-Jan-03 Tue
2017-Jan-04 Wed
2017-Jan-05 Thu
2017-Jan-06 Fri
2017-Jan-07 Sat
2017-Jan-08 Sun
2017-Jan-09 Mon
2017-Jan-10 Tue
2017-Jan-11 Wed
2017-Jan-12 Thu
2017-Jan-13 Fri
2017-Jan-14 Sat
2017-Jan-15 Sun
2017-Jan-16 Mon
2017-Jan-17 Tue
2017-Jan-18 Wed
2017-Jan-19 Thu
2017-Jan-20 Fri
2017-Jan-21 Sat
2017-Jan-22 Sun
2017-Jan-23 Mon
2017-Jan-24 Tue
2017-Jan-25 Wed
2017-Jan-26 Thu
2017-Jan-27 Fri
2017-Jan-28 Sat
2017-Jan-29 Sun
2017-Jan-30 Mon
2017-Jan-31 Tue
2035-Jan-23 is Tue
total 4 Sundays.
total 365 days of year.
You should use A bank, free days = 35


 备注

1.编译器版本gcc4.8.5,运行环境centos7 64位
2.本文只做简单记录用,详细用法请参考 Boost Library,或者是罗剑锋的 boost程序库完全开发指南 书本
3..原文地址http://www.freecls.com/a/2712/9b

  

©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。