时间和日历类的设计
C++
通用框架的设计
作者:
naven
1
介绍
时间和日历以及时间的格式化处理在软件的设计中起着非常重要的作用,但是目前
C++
的库却未有一个简单易用的时间类,大部分都需要开发者直接调用操作系统的
API
来完成,而且很多
API
都不是线程安全的。某些大型的
C++
框架虽然提供一些时间类,但是却不通用,也很难直接拿出来使用。下面介绍一下参考
Java Framework
中的时间相关的类来设计并实现
C++
版本的时间和日历类。
主要有如下一些类
Time
类,对应于
Java
的
java.util.Date
类,表示特定的瞬间,精确到毫秒(
Linux
可精确到微秒,
Solaris
可精确到十亿分之一秒)。
Time
只表示某时某地的瞬间,从
1970
年
1
月
1
日
00:00:00 GMT
以来的微秒数,无时区。
Calendar
类,对应于
Java
的
java.util.Calendar
类,它既表示了
Time
的精确瞬间,还代表了此时的年、月、日、时区等。它为特定瞬间与一组诸如
YEAR
、
MONTH
、
DAY_OF_MONTH
、
HOUR
等
日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用微秒值来表示,它是距历元(即格林威治标准时间
1970 年 1
月
1
日的
00:00:00.000
,
GMT
)的偏移量。
TimeFormat
类,类似
Java
的
java.text.SimpleDateFormat
类,它用来将时间和日历格式化成一个本地时间格式的文本形式,或者指定格式的文本形式。如果格式化时间,将缺省使用操作系统设定的本地(
locale
)时间格式处理。
TimeParser
类,类似
Java
的
java.text.SimpleDateFormat
类,与
TimeFormat
相反,它用来将一个时间的文本转化成一个本地时间
Time
,缺省使用操作系统设定的本地时间格式处理。
2
Hello World!
下面介绍一下它们的使用
void
main()
{
//
获取当前时间,精确到微秒
Time t
=
Time::getCurrentTime();
//
使用CRT的API格式化时间,只能精确到秒
time_t tt
=
t.sec();
printf(
"
\n%s\n
"
, ctime(
&
tt));
//
使用系统缺省的locale输出格式化时间文本
TimeFormat tf(
"
%c
"
);
printf(
"
\n%s\n
"
, tf.format(t).c_str());
//
使用系统缺省的locale输出格式化时间文本
TimeFormat tf2(
"
%#c
"
);
printf(
"
\n%s\n
"
, tf2.format(t).c_str());
//
自定义输出格式化时间文本,精确到豪秒
TimeFormat tff(
"
%Y-%m-%d %H:%M:%S.%q
"
);
printf(
"
\n%s\n
"
, tf2.format(t).c_str());
//
自定义输出格式化时间文本,精确到豪秒,输出所有时间信息,包括时区和年代等
TimeFormat tfCN(
"
%G %Y年%B%d日 %A %H时%M分%S秒%q豪秒 时区%z
"
,
"
zh_CN.gb2312
"
);
printf(
"
\n%s\n
"
, tfCN.format(t).c_str());
//
使用自定义 zh_CN.gb2312 的locale和字符集输出格式化时间文本,不受系统locale影响
TimeFormat tfCN2(
"
%G %Y %b %d %a %H:%M:%S.%q %z
"
,
"
zh_CN.gb2312
"
);
printf(
"
\n%s\n
"
, tfCN2.format(t).c_str());
//
使用自定义 en_US.iso8859-1 的locale和字符集输出格式化时间文本,不受系统locale影响
TimeFormat tfUS(
"
%G %d %B %Y %A %H:%M:%S.%q TZ:%z
"
,
"
en_US.iso8859-1
"
);
printf(
"
\n%s\n
"
, tfUS.format(t).c_str());
TimeFormat tfUS2(
"
%G %Y %b %d %a %H:%M:%S.%q %z
"
,
"
en_US.iso8859-1
"
);
printf(
"
\n%s\n
"
, tfUS2.format(t).c_str());
//
使用 MIME 标准格式输出格式化时间文本
TimeFormat tfMIME(
"
%a, %d %b %Y %H:%M:%S %z
"
);
printf(
"
\n%s\n
"
, tfMIME.format(t).c_str());
//
使用 MimeParse 方法转换时间
Time t2
=
tf.mimeParse(tf.mimeFormat(t));
printf(
"
\n%s\n
"
, tfCN.format(t2).c_str());
}
编译程序将输入如下结果
Wed Nov
9
16
:
09
:
40
2005
11
/
09
/
05
16
:
09
:
40
Wednesday, November
09
,
2005
16
:
09
:
40
Wednesday, November
09
,
2005
16
:
09
:
40
公元 2005年十一月09日 星期三 16时09分40秒078豪秒 时区
+
0800
公元
2005
11月
09
周三
16
:
09
:
40.078
+
0800
AD
09
November
2005
Wednesday
16
:
09
:
40.078
TZ:
+
0800
AD
2005
Nov
09
Wed
16
:
09
:
40.078
+
0800
Wed,
09
Nov
2005
16
:
09
:
40
+
0800
公元 2005年十一月09日 星期三 16时09分40秒000豪秒 时区
+
0800
3
Time
类
由于
Time
要精确到微秒,所以
Time
类使用
timeval
结构存储时间,该结构包含两个
long
整形,一个表示秒数(从
1970
年
1
月
1
日
00:00:00 GMT
以来的偏移量),一个表示微秒数。
Time
类的定义如下
class
Time
{
private
:
/**/
/*
*
* Store the values as a timeval which fields as.
* struct timeval {
* long tv_sec; // seconds
* long tv_usec; // microseconds
*/
struct
timeval _tv;
}
Time
类获取当前精确到微秒的实现如下(
Win32
提供的
API
只能精确到豪秒)
Time
Time::gettimeofday()
{
#if
defined(HAVE_GETTIMEOFDAY)
struct
timeval tp;
tp.tv_sec
=
0
;
tp.tv_usec
=
0
;
#ifdef IS_SOLARIS_OS
::gettimeofday(
&
tp,
0
);
//
microseconds = 1/1,000,000 sec
Time nowtime(tp);
#else
struct
timezone tz;
tz.tz_dsttime
=
0
;
tz.tz_minuteswest
=
0
;
::gettimeofday(
&
tp,
&
tz);
//
microseconds = 1/1,000,000 sec
Time nowtime(tp);
#endif
return
nowtime;
#elif
defined(HAVE_FTIME)
struct
timeb tb;
tb.dstflag
=
0
;
tb.millitm
=
0
;
tb.time
=
0
;
tb.timezone
=
0
;
ftime(
&
tb);
//
milliseconds = 1/1,000 sec
Time nowtime(tb);
return
nowtime;
#elif
defined(HAVE_CLOCK_GETTIME)
struct
timespec ts;
ts.tv_sec
=
0
;
ts.tv_nsec
=
0
;
::clock_gettime(CLOCK_REALTIME,
&
ts);
//
nanoseconds = 1/1,000,000,000 sec
Time nowtime(ts);
return
nowtime;
#else
//
#warning "Time::gettimeofday()- low resolution timer: gettimeofday and ftime unavailable"
Time nowtime(::time(
0
),
0
);
//
seconds
return
nowtime;
#endif
}
Time
类提供很多方法如果构造方法和操作符等,可以在
time_t
和其他时间类型之间转换,也可以单独获取和设置时间的秒和微秒。
4
Calendar
类
Calendar
类是一个表示日历的类,它可以实现日历的向前向后前进等所有功能。例如你可以设置,获取,和操纵一个日期对象的各个部分,比方一个月的一天或者是一个星期的一天。举例如下:
//
定义日历对象并设置为当前时间
Time nowtm
=
Time::getCurrentTime();
TimeFormat ntf(
"
%Y-%m-%d %H:%M:%S.%q
"
);
printf(
"
\n%s\n
"
, ntf.format(nowtm).c_str());
Calendar cal;
cal.setTime(nowtm);
//
年月日都向前移动一单位
cal.rollUpYear();
cal.rollUpMonth();
cal.rollUpDayOfMonth();
String scal;
ntf.format(cal, scal);
printf(
"
\n%s\n
"
, scal.c_str());
程序输出结果
2005
-
11
-
09
16
:
45
:
54.589
2006
-
12
-
10
16
:
45
:
54.589
Calendar
类是建立在
Time
类的基础上的,并加入了时区等信息,它的定义看起来如下所示:
class
Calendar
{
protected
:
/**/
/*
*
* Value of the <code>ERA</code> field indicating
* the period before the common era (before Christ), also known as BCE.
* The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
* , 2 BC, 1 BC, 1 AD, 2 AD,
* @see Calendar#ERA
*/
int
_era;
/**/
/*
*
* The currently set time for this calendar, expressed in milliseconds after
* January 1, 1970, 0:00:00 GMT.
* @see #isTimeSet
* @serial
*/
Time _time;
/**/
/*
*
* The <code>TimeZone</code> used by this calendar. </code>Calendar</code>
* uses the time zone data to translate between locale and GMT time.
* @serial
*/
struct
timezone _zone;
/**/
/*
*
* The asctime() and mktime() functions both take an argument
* representing broken-down time which is a binary represen-
* tation separated into year, month, day, etc. Broken-down
* time is stored in the structure tm which is defined in
* <time.h> as follows:<P>
* <code>
* struct tm
* {
* int tm_sec; // seconds
* int tm_min; // minutes
* int tm_hour; // hours
* int tm_mday; // day of the month
* int tm_mon; // month
* int tm_year; // year
* int tm_wday; // day of the week
* int tm_yday; // day in the year
* int tm_isdst; // daylight saving time
* };
* </code>
*/
struct
tm _tm;
}
Calendar
类定义了很多方法和操作符用来在
Time
类和时区、年月日等之间转换和设置、读取等。
Calendar
类实现时间的生成、转换等都是自己实现的,并不调用操作系统的
API
如
mktime()
等,并不使用
CRT
(
C
运行时)的全局变量如
timezone
等,所以它是线程安全的,每一个
Calendar
对象都是互相独立的,拥有自己的时区等信息。
5
TimeFormat
类
TimeFormat
类主要实现了将时间格式化成一个时间文本,可以使用系统缺省的本地格式,也可以指定格式转换。转换的用法如下:
TimeFormat tf(
"
%Y-%m-%d %H:%M:%S.%q
"
);
//
定义一个格式
Time t
=
Time::getCurrentTime();
String s
=
tf.format(t);
//
将时间对象格式化成文本字符串
时间格式化
pattern
有如下几种
%a The abbreviated weekday name according to the current locale.
%A The full weekday name according to the current locale.
%b The abbreviated month name according to the current locale.
%B The full month name according to the current locale.
%c The preferred date and time representation for the current locale.
%C The century number (year/100) as a 2-digit integer. (SU)
%d The day of the month as a decimal number (range 01 to 31).
%D Equivalent to %m/%d/%y. (Yecch - for Americans only.
Americans should note that in other countries
%d/%m/%y is rather common. This means that in international context
this format is ambiguous and should not be used.) (SU)
%e Like %d, the day of the month as a decimal number, but a leading
zero is replaced by a space. (SU)
%E Modifier: use alternative format, see below. (SU)
%G The ISO 8601 year with century as a decimal number. The 4-digit
year corresponding to the ISO week number (see %V). This has the
same format and value as %y, except that if the ISO week number
belongs to the previous or next year, that year is used instead. (TZ)
%g Like %G, but without century, i.e., with a 2-digit year (00-99). (TZ)
%h Equivalent to %b. (SU)
%H The hour as a decimal number using a 24-hour clock (range 00 to 23).
%I The hour as a decimal number using a 12-hour clock (range 01 to 12).
%j The day of the year as a decimal number (range 001 to 366).
%k The hour (24-hour clock) as a decimal number (range 0 to 23); single
digits are preceded by a blank. (See also %H.) (TZ)
%l The hour (12-hour clock) as a decimal number (range 1 to 12); single
digits are preceded by a blank. (See also %I.) (TZ)
%m The month as a decimal number (range 01 to 12).
%M The minute as a decimal number (range 00 to 59).
%n A newline character. (SU)
%O Modifier: use alternative format, see below. (SU)
%p Either `AM' or `PM' according to the given time value, or the
corresponding strings for the current locale. Noon is treated as `pm'
and midnight as `am'.
%P Like %p but in lowercase: `am' or `pm' or a corresponding string for
the current locale. (GNU)
%r The time in a.m. or p.m. notation. In the POSIX locale this is
equivalent to `%I:%M:%S %p'. (SU)
%R The time in 24-hour notation (%H:%M). (SU) For a version including the
seconds, see %T below.
%s The number of seconds since the Epoch, i.e., since 1970-01-01 00:00:00 UTC.
(TZ)
%S The second as a decimal number (range 00 to 61).
%t A tab character. (SU)
%T The time in 24-hour notation (%H:%M:%S). (SU)
%u The day of the week as a decimal, range 1 to 7, Monday being 1.
See also %w. (SU)
%U The week number of the current year as a decimal number, range 00 to 53,
starting with the first Sun? day as the first day of week 01.
See also %V and %W.
%V The ISO 8601:1988 week number of the current year as a decimal number,
range 01 to 53, where week 1 is the first week that has at least 4 days
in the current year, and with Monday as the first day of the week.
See also %U and %W. (SU)
%w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u.
%W The week number of the current year as a decimal number, range 00 to 53,
starting with the first Mon? day as the first day of week 01.
%x The preferred date representation for the current locale without the time.
%X The preferred time representation for the current locale without the date.
%y The year as a decimal number without a century (range 00 to 99).
%Y The year as a decimal number including the century.
%z The time-zone as hour offset from GMT. Required to emit RFC822-conformant
dates (using "%a, %d %b %Y %H:%M:%S %z"). (GNU)
%Z The time zone or name or abbreviation.
%+ The date and time in date(1) format. (TZ)
%% A literal `%' character.
6
TimeParser
类
TimeParser
类实现与
TimeFormat
相反的功能,是将一个指定格式的时间文本转换成时间
Time
对象或
Calendar
对象,它的设计与
TimeFormat
类似,目前还未全部完成,只实现了转换
Mime
时间格式的文本的功能。
示例见上面的
Hello World
程序。
C++
通用框架的设计
作者:
naven
日期:
2005-11-9
posted on 2005-11-09 17:28
Javen-Studio 阅读(415)
评论(3) 编辑 收藏收藏至365Key