目錄
第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日。