C++时间库(三) Boost.Date_Time库

文章目录

  1. 1. Gregorian
    1. 1.1. Date
    2. 1.2. Date Duration
    3. 1.3. Date Period
  2. 2. Posix Time
    1. 2.1. Ptime
    2. 2.2. Time Duration
    3. 2.3. Time Period
  3. 3. Local Time
    1. 3.1. Time Zone(抽象)
    2. 3.2. Posix Time Zone
    3. 3.3. Time Zone Database
      1. 3.3.1. Local Date Time
    4. 3.4. Local Time Period
  4. 4. Date Time Input/Output
    1. 4.1. IO对象
    2. 4.2. Formatter/Parser对象
  5. 5. 总结

前面两节,总结了C风格的时间函数和C++标准库std::chrono,作为C++的一个重要的开发库Boost,它提供了两个时间库Boost.Chrono和Boost.Date_Time,这里只对Boost.Date_Time库进行简单地总结和梳理,没有面面俱到,详细说明可以参考Boost.Date_Time

Gregorian

是一个基于公历的日期库,Boost.DateTime支持从1400年至9999年的历法日期。
所有gregorian类型都在boost::gregorian命名空间下。没有input/output依赖的类包含在boost/date_time/gregorian/gregorian_types.hpp中,boost/date_time/gregorian/gregorian.hpp包含所有类型和input/output代码。
主要类型:datedate_durationdate_perioddate_iterator

Date

date代表了一个日期,由年、月、日组成。
它可以从年月日进行构造

1
date(greg_year, greg_month, greg_day)

从字符串构造

1
2
3
4
5
6
7
8
date from_string(std::string)
date from_undelimited_string(std::string)

std::string ds("2002/1/25");
date d(from_string(ds));

std::string ds("20020125");
date d(from_undelimited_string(ds));

从clock构造

1
2
date d(day_clock::local_day()); //Get the local day based on the time zone settings of the computer.
date d(day_clock::universal_day()); //Get the UTC day.

从结构体tm创建

1
2
3
4
5
6
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

可以转换成字符串

1
2
3
std::string to_simple_string(date d) //"2002-Jan-01"
std::string to_iso_string(date d) //"20020131"
std::string to_iso_extended_string(date d) //"2002-01-31"

可以转换成结构体tm

1
2
3
4
5
6
7
8
9
10
11
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 */

能进行加减算术运算和逻辑运算。

Date Duration

boost::gregorian::date_duration表示时间长度,被用做的gregorian::date的算术运算,可正可负。
boost::gregorian::date_durationtypedefdays
这里还包括其它duration类型:monthsyearsweeks

Date Period

boost::gregorian::date_period表示两个日期之间的区间。利用它可以检测某个日期是否在某个假日或者周末内,可以计算一个时间区间与另一个时间区间的交集或者并集等。
可以用两个日期或者一个日期和一个时间长度进行构造:

1
2
3
4
date_period dp(date(2002,Jan,10),
date(2002,Jan,12));
date_period dp(date(2002,Jan,10),
days(2));

Posix Time

定义了一个非调节的时间系统,这个系统具有纳秒/毫秒精度和稳定计算的特性。对于ptime,纳秒精度下使用96 bits存储,毫秒精度下使用64 bits存储。这个时间系统使用公历(Gregrorian calendar)去表示时间中的日期部分。

Ptime

boost::posix_time::ptime表示一个与时区无关的时间点,日期部分依赖于gregorian::date
注意
此时间点与时区无关,例如:
ptime t(second_clock::local_time());
此时的时间t是本地时间。
ptime t(second_clock::universal_time());
而此时的时间t是UTC时间。

使用日期加时间偏移构造:

1
2
3
4
ptime t1(date(2002,Jan,10),
time_duration(1,2,3));
ptime t2(date(2002,Jan,10),
hours(1)+nanosec(5));

从字符串创建:

1
2
3
4
5
std::string ts("2002-01-20 23:59:59.000");
ptime t(time_from_string(ts))

std::string ts("20020131T235959");
ptime t(from_iso_string(ts))

从时钟构造:

1
2
3
4
5
6
7
ptime t(second_clock::local_time()); //本地时间

ptime t(second_clock::universal_time()) //UTC时间

ptime t(microsec_clock::local_time());

ptime t(microsec_clock::universal_time());

使用转换函数创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//time_t -> ptime
ptime from_time_t(time_t t);

//FILETIEM -> ptime
ptime from_ftime<ptime>(FILETIME ft);

//tm -> ptime
ptime ptime_from_tm(tm timetm)

tm pt_tm;

pt_tm.tm_year = 105;
pt_tm.tm_mon = 0;
pt_tm.tm_mday = 1;
pt_tm.tm_hour = 1;
pt_tm.tm_min = 2;
pt_tm.tm_sec = 3;
ptime pt = ptime_from_tm(pt_tm);
// pt => 2005-Jan-01 01:02:03

转换成字符串

1
2
3
4
5
std::string to_simple_string(ptime) //2002-Jan-01 10:00:01.123456789

std::string to_iso_string(ptime) //20020131T100001,123456789

std::string to_iso_extended_string(ptime) //2002-01-31T10:00:01,123456789

转换成结构体tm

1
2
3
4
5
6
7
8
9
10
11
ptime pt(date(2005,Jan,1), time_duration(1,2,3));
tm pt_tm = to_tm(pt);
/* tm_year => 105
tm_mon => 0
tm_mday => 1
tm_wday => 6 (Saturday)
tm_yday => 0
tm_hour => 1
tm_min => 2
tm_sec => 3
tm_isddst => -1 */

Time Duration

boost::posix_time::time_duration代表时间长度,可正可负。
下面展示了几个继承自time_duration的辅助类:
time_duration_inherit

1
2
3
4
using namespace boost::posix_time;

time_duration td = hours(1) + seconds(10); //01:00:10
td = hours(1) + nanoseconds(5); //01:00:00.000000005

构造函数:

1
2
3
4
time_duration(hours,
minutes,
seconds,
fractional_seconds)

可以使用hours,minutes,seconds,milliseconds,microseconds,nanoseconds来构造:

1
2
3
time_duration td = hours(3);

time_duration td = milliseconds(3);

还记得上一节在std::chrono命名空间下也有hours,minutes,seconds,milliseconds,microseconds,nanoseconds这些类型,不要混了。

从字符串创建:

1
2
std::string ts("23:59:59.000");
time_duration td(duration_from_string(ts));

转换成结构体tm:

1
2
3
4
5
6
7
8
9
10
11
time_duration td(1,2,3);
tm td_tm = to_tm(td);
/* tm_year => 0
tm_mon => 0
tm_mday => 0
tm_wday => 0
tm_yday => 0
tm_hour => 1
tm_min => 2
tm_sec => 3
tm_isddst => -1 */

Time Period

boost::posix_time::time_period表示两个时间的区间。类似于date_period

用两个时间点来构造:

1
2
3
4
5
6
7
8
date d(2002,Jan,01);
ptime t1(d, seconds(10)); //10 sec after midnight
ptime t2(d, hours(10)); //10 hours after midnight
time_period tp(t1, t2); //Create a period as [begin, end). If end is <= begin then the period will be defined as invalid.

date d(2002,Jan,01);
ptime t(d, seconds(10)); //10 sec after midnight
time_period tp(t, hours(3)); //Create a period as [begin, begin+len) where end would be begin+len. If len is <= zero then the period will be defined as invalid.

Local Time

这个库包括四个主要的本地时间管理扩展。
local_date_time本地时间
posix_time_zone由posix字符串(”EST10EDT,M10.5.0,M3.5.0/03”)定义的时区
time_zone_database从.csv文件中用区域获取时区
time_zone抽象的时区接口

这些扩展定义了一个用于调整时间到本地时区的时间系统。这个时间系统使用了posix_time系统的所有特性和优点。time_zone包含用于时区转换的所有必要数据/规则。

Time Zone(抽象)

time_zone_base是表示时区的一个抽象基类模板。date_time库靠boost::shared_ptr<time_zone_base>来处理时区。为了使用方便,time_zone_basetypedeftime_zone

Posix Time Zone

一个posix_time_zone对象包含一个时区的数据和规则,像距离UTC时间的偏移、名称、缩写和夏令时规则。

Time Zone Database

本地时间系统依赖于时区信息的存储。时区数据库就是用来存储这些数据的。

Local Date Time

local_date_time就是一个时间点和对应的时区。时间在内部用UTC表示。

从clock构造:

1
2
3
4
5
6
7
8
9
10
11
12
time_zone_ptr zone(
new posix_time_zone("MST-07")
);
local_date_time ldt =
local_microsec_clock::local_time(
zone);

time_zone_ptr zone(
new posix_time_zone("MST-07")
);
local_date_time ldt =
local_sec_clock::local_time(zone);

从ptime构造:

1
2
3
4
5
6
// 3am, 2004-Nov-05 local time
ptime pt(date(2004,Nov,5),
hours(10));
time_zone_ptr zone(
new posix_time_zone("MST-07"));
local_date_time az(pt, zone);

转换成结构体tm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 6am, 2005-Jul-05 local time
std::string z("EST-05EDT,M4.1.0,M10.1.0");
ptime pt(date(2005,Jul,5),
hours(10));
time_zone_ptr zone( new posix_time_zone(z));
local_date_time ldt(pt, zone);
tm ldt_tm = to_tm(ldt);
/* tm_year => 105
tm_mon => 6
tm_mday => 5
tm_wday => 2 (Tuesday)
tm_yday => 185
tm_hour => 6
tm_min => 0
tm_sec => 0
tm_isddst => 1 */

Local Time Period

boost::local_time::local_time_period表示两个本地时间的区间,与date_periodtime_period类似。

Date Time Input/Output

IO streaming system给用户提供了灵活的日期和时间展示方式。其自定义项分为两部分:格式化标识和字符串元素。格式化标识提供了日期元素和日期类型的组织顺序上的灵活性,自定义字符串元素允许替换内建的月份名称、周名称等其它IO内建的字符串。
输出系统基于date_facet(派生自std::facet),输入系统基于date_input_facet

IO对象

Output Input
date_facet date_input_facet
wdate_facet wdate_input_facet
time_facet time_input_facet
wtime_facet wtime_input_facet
local_time_facet* local_time_input_facet*
wlocal_time_facet* wlocal_time_input_facet*

Formatter/Parser对象

Output Input
period_formatter period_parser
date_generator_formatter date_generator_parser
special_values_formatter special_values_parser
null format_date_parser

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
date d(2004, Feb, 29);
time_duration td(12,34,56,789);
stringstream ss;
ss << d << ' ' << td;
ptime pt(not_a_date_time);
cout << pt << endl; // "not-a-date-time"
ss >> pt;
cout << pt << endl; // "2004-Feb-29 12:34:56.000789"
ss.str("");
ss << pt << " EDT-05EDT,M4.1.0,M10.5.0";
local_date_time ldt(not_a_date_time);
ss >> ldt;
cout << ldt << endl; // "2004-Feb-29 12:34:56.000789 EDT"

local_time_facet* output_facet = new local_time_facet();
local_time_input_facet* input_facet = new local_time_input_facet();
ss.imbue(locale(locale::classic(), output_facet));
ss.imbue(locale(ss.getloc(), input_facet));

output_facet->format("%a %b %d, %H:%M %z");
ss.str("");
ss << ldt;
cout << ss.str() << endl; // "Sun Feb 29, 12:34 EDT"

output_facet->format(local_time_facet::iso_time_format_specifier);
ss.str("");
ss << ldt;
cout << ss.str() << endl; // "20040229T123456.000789-0500"

output_facet->format(local_time_facet::iso_time_format_extended_specifier);
ss.str("");
ss << ldt;
cout << ss.str() << endl; // "2004-02-29 12:34:56.000789-05:00"

示例2,这是一个格式化时间的函数,应用最多的应该是格式化time_t时间(第二个函数)。

1
2
3
4
5
6
7
8
9
10
11
12
std::string FormatTime(const ptime& pt, const char* time_format) {
std::stringstream stream;
std::locale currlocale(std::locale::classic(),
new time_facet(time_format));
stream.imbue(currlocale);
stream << pt;
return stream.str();
}

std::string FormatLocalTime(std::time_t t, const char* time_format) {
return FormatTime(local_adj::utc_to_local(from_time_t(t)), time_format);
}

注意:
std::ios_base::imbue就是设置本地化。
C++输入/输出库中的每一个stream对象都会关联一个locale对象,locale对象会使用facet去解析和格式化所有的数据。此外,每一个std::basic_regxe对象会关联一个locale对象。locale对象还可以用于标准容器和算法执行字符串排序时的断言。

注意
std::locale构造函数的第二个参数facet,需要在堆中分配,如果使用局部变量(对象在栈中),会引起程序崩溃,而且最后也不要手工delete这个facet对象,因为std::locale在析构中会自动释放内存。
参看Boost DateTime, Locales and Facets

总结

总的来说Boost.Date_Time库比较庞大,提供的功能非常多,使用也非常方便,但是细节比较多,这里只能简单得梳理一下,下一节将总结一下三个库。


版权声明

本博客 采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可

本文永久链接:http://yoursite.com/2016/01/06/C++时间库(三)/