目录
第1章基本概念
1.1 基本概念
GMT(Greenwich Mean Time)是格林尼治标准时间。它是通过观测太阳来确定时间的,即力学时。力学时的精确度不是很高,所以它被协调世界时(Coordinate Universal Time,简称UTC)所取代。UTC采用原子钟计时,所以它的精确度很高。Windows中,GMT和UTC没有区别,被统称为系统时间(System Time)。
标准时(Standard Time)等于UTC时间加上时差,如:中国的时区为+8:00,北京时间就是UTC时间加上8小时。
某些国家在夏季还将执行夏令时,也就是日光节能时(Daylight Saving Time,简称DST)。就是在夏季将时钟拨快1小时,早起早睡充分利用太阳光以达到节约能源的目的。UTC时间、标准时、夏令时的关系请参考下面两张图形:
图1.1 北半球一年内的时间
图1.2 南半球一年内的时间
Windows中,标准时和夏令时被统称为本地时间(Local Time)。本地时间有时会有歧义,如图1.1和图1.2中的绿色部分,它所表示的本地时间是标准时还是夏令时?
1.2 时间表示法
VC中对时间的表示一般有两种方法。一种是人们熟知的年、月、日、时、分、秒,如:SYSTEMTIME、struct tm,这种表示方法被称之为broken-down time。
另一种是从基准时刻到当前时刻的时间间隔,如:time_t表示1970年1月1日到当前时刻的秒数,称这种表示方法为calendar time。类似的还有FILETIME,它其实就是一个__int64,表示1601年1月1日到当前时刻的时间间隔(单位10-7 秒,即100纳秒,万分之一毫秒)。
第2章 Win32 API
2.1 获取
2.1.1 时间间隔
GetTickCount和GetTickCount64返回启动Windows后到现在的毫秒数。GetTickCount返回一个DWORD,最大为0xFFFFFFFF秒,约为49.71天。也就是说连续运行Windows系统 50 天后,GetTickCount会从零开始计时。
GetTickCount64返回一个unsigned __int64,最大为0xFFFFFFFFFFFFFFFF秒,约为 5.8亿年。再也不用担心计时重新归零的问题了。
2.1.2 时刻
GetSystemTime用于获取毫秒级UTC时刻。
GetSystemTimeAsFileTime用于获取10-7 秒级的UTC时刻。
GetLocalTime用于获取本地时刻。要想知道这个时刻为标准时还是夏令时请通过GetTimeZoneInformation的返回值进行判断:返回TIME_ZONE_ID_DAYLIGHT表示夏令时,返回TIME_ZONE_ID_STANDARD和TIME_ZONE_ID_UNKNOWN表示标准时。TIME_ZONE_ID_UNKNOWN还表明了系统未启用夏令时。
GetFileTime用于获取打开文件(或文件夹)的UTC时刻。为了获取未打开文件的UTC时刻,请使用FindFirstFile函数。
2.1.3 时区
GetTimeZoneInformation函数可以获取时区信息,包括:时差、标准时偏差、夏令时偏差、夏令时开始时刻(标准时)、夏令时结束时刻(夏令时)。它获取的时区信息保存在结构TIME_ZONE_INFORMATION内:
typedef struct _TIME_ZONE_INFORMATION { // tzi
LONG Bias;
WCHAR StandardName[32];
SYSTEMTIME StandardDate;
LONG StandardBias;
WCHAR DaylightName[32];
SYSTEMTIME DaylightDate;
LONG DaylightBias;
} TIME_ZONE_INFORMATION;
这个结构各个成员变量的含义请参考下图:
图2.1 时区信息
Bias是时区时差的相反数,StandardBias为标准时偏差(没发现不为零的情况),DaylightBias为夏令时偏差(一般为-60),它们的单位都是分钟。UTC与标准时、夏令时的转换公式如下:
UTC=标准时 + Bias + StandardBias
UTC=夏令时 + Bias + DaylightBias
DaylightDate是夏令时的开始时刻,它是标准时。DaylightDate 各个成员变量的含义如下:
成员变量 |
含义 |
示例数值 |
wYear; |
年,一般为零 |
0 |
wMonth; |
月。0表示没有夏令时 |
4 |
wDayOfWeek; |
0至6分别表示星期日至星期六 |
1 |
wDay; |
第几个,范围[1,5]5表示最后一个。 |
0 |
wHour; |
时 |
2 |
wMinute; |
分 |
0 |
wSecond; |
秒 |
0 |
wMilliseconds; |
毫秒 |
0 |
以上表为例,夏令时的开始时刻为每年4月的第1个星期日的2:00:00.000
StandardDate是夏令时的结束时刻,它是夏令时。StandardDate各个成员变量的含义请参考上表。
注意:对于北半球而言,DaylightDate小于StandardDate,但是到了南半球则正好相反。
因为夏令时的开始、结束时间可能是变化的,自Vista后引入了下面两个函数:
GetTimeZoneInformationForYear
GetDynamicTimeZoneInformation
2.1.4 时区信息
时区信息全部存放在注册表里:
对于Windows 98而言,存放在如下位置:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Time Zones
对于Windows NT而言,存放在如下位置:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
对于Windows CE而言,存放在如下位置:
HKEY_LOCAL_MACHINE\Time Zones
如:修改WinCE时区为北京时间:
[HKEY_LOCAL_MACHINE\Time Zones]
"Default"="China Standard Time"
注册表里的二进制数据TZI,其结构如下:
#pragma pack(push,1)
class TZI
{
LONG Bias; //时差,单位:分钟
LONG StandardBias; //标准时差,单位:分钟
LONG DaylightBias; //夏令时时差,单位:分钟
SYSTEMTIME StandardDate; //夏令时结束时刻
SYSTEMTIME DaylightDate; //夏令时开始时刻
};
#pragma pack(pop)
2.2 设置
2.2.1 时刻
SetSystemTime用于设置Windows的UTC时刻。
SetLocalTime用于设置Windows的本地时刻。如果Windows启用了夏令时,有时会出现意想不到地后果。举例说明:假定系统时区为-8:00,并启用了夏令时。现在调用代码 SetLocalTime(2000.07.07 10:11:12),将会有两种不同的结果:
如果当前系统正处于夏令时,首先把2000.07.07 10:11:12转换为UTC时刻,即2000.07.07 10:11:12+7:00=2000.07.07 17:11:12,然后调用SetSystemTime(2000.07.07 17:11:12)。因为2000.07.07 17:11:12处于夏令时,所以最终的本地时刻为2000.07.07 17:11:12—7:00=2000.07.07 10:11:12,这是一个令人满意的结果。
如果当前系统处于标准时,首先把2000.07.07 10:11:12转换为UTC时刻,即2000.07.07 10:11:12+8:00=2000.07.07 18:11:12,然后调用SetSystemTime(2000.07.07 18:11:12)。因为2000.07.07 18:11:12处于夏令时,所以最终的本地时刻为2000.07.07 18:11:12—7:00=2000.07.07 11:11:12,这个结果实在令人不可思议!
SetFileTime用于修改某个打开文件(或文件夹)的UTC时刻。不打开文件,如何修改其时刻?
2.2.2 时区
SetTimeZoneInformation
SetDynamicTimeZoneInformation
2.2.3 时间基准
将计算机的BIOS时间当作本地时间
REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation] "RealTimeIsUniversal"=dword:00000000 |
将计算机的BIOS时间当作UTC时间
REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation] "RealTimeIsUniversal"=dword:00000001 |
2.3 比较
CompareFileTime
2.4 转换
2.4.1 DOS时间与FILETIME转换
DosDateTimeToFileTime
FileTimeToDosDateTime
2.4.2 SYSTEMTIME与FILETIME转换
FileTimeToSystemTime
SystemTimeToFileTime
2.4.3 本地时间与UTC时间转换
FileTimeToLocalFileTime
LocalFileTimeToFileTime
如果Windows启用了夏令时,上面两个函数是无法正常工作的。如假定系统时区为-8:00,并启用了夏令时。则将UTC时刻转换为本地时刻将用到如下两个公式:
夏令时=UTC-7:00
标准时=UTC-8:00
正确的做法是:首先根据UTC时刻判断本地时刻是夏令时还是标准时,然后选择公式进行计算。但上面两个函数不是这么工作的,它们根据Windows当前处于夏令时还是标准时选择公式进行计算。
SystemTimeToTzSpecificLocalTime
TzSpecificLocalTimeToSystemTime
第3章 C运行时库函数
3.1 获取
3.1.1 时间间隔
3.1.1.1 clock
原型:clock_t clock( void )
功能:返回进程已经运行的时间,单位:1 / CLOCKS_PER_SEC 秒。
注意:clock_t其实就是long。
3.1.2 时刻
3.1.2.1 time, _time32, _time64
原型:time_t time( time_t *timer );
功能:返回当前UTC时刻。
说明:
1、返回值表示自 1970 年 1 月 1 日到当前时刻的秒数;
2、在VC++6.0中,没有_time32, _time64。time_t相当于long。因此,time_t最多只能表示到 2038-01-19 03:14:07;
3、在VC++2005中,_time32的返回值为long,_time64的返回值为__int64。至于time的返回值则要取决于是否定义了宏_USE_32BIT_TIME_T,定义了就是long,未定义就是__int64。
3.1.2.2 _ftime
原型:void _ftime( struct _timeb *timeptr );
功能:获得当前UTC时刻、时差、是否为夏令时等信息。
说明:
1、与time函数相比,_ftime获得的时间精度更高(包含毫秒),信息更加丰富,如:包含时差信息。具体的请参考_timeb结构:
struct _timeb
{
time_t time; //UTC时刻
unsigned short millitm; //毫秒
short timezone; //时差= UTC时刻 -本地时刻,单位:分钟
short dstflag; //非零表示目前正处于夏令时
};
3.1.2.3 _stat、_fstat
用于获取文件时间
3.1.2.4 _strdate
获取当前UTC日期至一个字符串内
3.1.2.5 _strtime
获取当前UTC时间至一个字符串内
3.2 设置
3.2.1 时刻
_utime、_futime用于修改文件的访问、修改时刻,它们的不同之处在于指定文件的方式不同:前者通过路径名指定文件,后者通过文件句柄指定文件。
3.2.2 时区
请使用 _tzset 函数
3.3 比较
请使用 difftime 函数
3.4 转换
3.4.1 time_t与struct tm
struct tm 结构如下:
struct tm
{
int tm_sec; //秒[0,59]
int tm_min; //分[0,59]
int tm_hour; //时[0,23]
int tm_mday; //日[1,31]
int tm_mon; //月减去一[0,11]
int tm_year; //年减去1900
int tm_wday; //星期[0,6],0表示周日
int tm_yday; //年积日[0,365]
int tm_isdst; //正数表示为夏令时,0表示标准时,小于零表示未知
};
它既可以表示UTC时刻,也可以表示本地时刻。表示本地时刻时,通过tm_isdst可以明确指定该时刻为标准时刻还是夏令时刻。
3.4.1.1 time_t(UTC时刻)转换为 struct tm(UTC时刻)
请使用 gmtime 函数
3.4.1.2 struct tm(UTC时刻)转换为 time_t(UTC时刻)
请使用 _mkgmtime 函数
3.4.1.3 time_t(UTC时刻)转换为 struct tm(本地时刻)
请使用 localtime 函数
3.4.1.4 struct tm(本地时刻)转换为 time_t(UTC时刻)
请使用 mktime 函数
原型:time_t mktime( struct tm *timeptr );
说明:
1、timeptr-> tm_isdst为正数(一般为1)时,表示将夏令时转换为UTC时刻;
2、timeptr-> tm_isdst为零时,表示将标准时转换为UTC时刻;
3、timeptr-> tm_isdst为负数(一般为-1)时,函数将自动判断本地时刻是夏令时还是标准时,然后再转换为UTC时刻。注意:夏令时、标准时的判断并不能完全正确;
3.5 格式化
3.5.1 asctime
将struct tm转换为字符串格式的时间
3.5.2 ctime
将time_t转换为字符串格式的时间
3.5.3 strftime
将struct tm格式化输出为字符串
第4章 MFC
MFC中,CTime和COleDateTime可用于处理时间。它们的异同:
1、CTime封装的是C函数,COleDateTime封装的是Win32 API;
2、CTime可以处理夏令时,COleDateTime没有此功能;
3、CTime以一个整数表示时刻,COleDateTime以一个double表示时刻。它们都只能精确到秒。
4、VC++6.0的CTime使用long表示时刻,时间范围为 1970年1月1日至2038年1月18日。自VC++2002以后,CTime使用__int64表示时刻,时间范围为1970年1月1日 12:00:00至3000年12月31日。
COleDateTime 表示的时间范围:100年1月1日至9999年12月31日。