文章目录
前面两节,总结了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代码。
主要类型:date
、date_duration
、date_period
、date_iterator
Date
date
代表了一个日期,由年、月、日组成。
它可以从年月日进行构造1
date(greg_year, greg_month, greg_day)
从字符串构造1
2
3
4
5
6
7
8date 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
2date 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
6tm 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
3std::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"
可以转换成结构体tm1
2
3
4
5
6
7
8
9
10
11date 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_duration
被typedef
成days
。
这里还包括其它duration类型:months
,years
,weeks
。
Date Period
boost::gregorian::date_period
表示两个日期之间的区间。利用它可以检测某个日期是否在某个假日或者周末内,可以计算一个时间区间与另一个时间区间的交集或者并集等。
可以用两个日期或者一个日期和一个时间长度进行构造:1
2
3
4date_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
4ptime t1(date(2002,Jan,10),
time_duration(1,2,3));
ptime t2(date(2002,Jan,10),
hours(1)+nanosec(5));
从字符串创建:1
2
3
4
5std::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
7ptime 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
5std::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
转换成结构体tm1
2
3
4
5
6
7
8
9
10
11ptime 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
的辅助类:1
2
3
4using 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
4time_duration(hours,
minutes,
seconds,
fractional_seconds)
可以使用hours
,minutes
,seconds
,milliseconds
,microseconds
,nanoseconds
来构造:1
2
3time_duration td = hours(3);
time_duration td = milliseconds(3);
还记得上一节在std::chrono命名空间下也有hours
,minutes
,seconds
,milliseconds
,microseconds
,nanoseconds
这些类型,不要混了。
从字符串创建:1
2std::string ts("23:59:59.000");
time_duration td(duration_from_string(ts));
转换成结构体tm:1
2
3
4
5
6
7
8
9
10
11time_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
8date 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_base
被typedef
成time_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
12time_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_period
和time_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
33date 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
12std::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库比较庞大,提供的功能非常多,使用也非常方便,但是细节比较多,这里只能简单得梳理一下,下一节将总结一下三个库。
版权声明