C库中与系统时间相关的函数定义在<time.h>头文件中, C++定义在<ctime>头文件中,Windows系统API调用获取时间的系统API时需要 #include<Windows.h>。下面为基本概念,有助于理解后面API功能使用的理解。
Coordinated Universal Time(UTC)协调世界时,又称为世界标准时间,也就是大家所熟知的格林威治标准时间(Greenwich Mean Time,GMT)。比如,中国内地的时间与UTC的时差为+8,也就是UTC+8。美国是UTC-5。
Calendar Time 日历时间,是用“从一个标准时间点到此时的时间经过的秒数”来表示的时间。这个标准时间点对不同的编译器来说会有所不同,但对一个编译系统来说,这个标准时间点是不变的,该编译系统中的时间对应的日历时间都通过该标准时间点来衡量,所以可以说日历时间是“相对时间”,但是无论你在哪一个时区,在同一时刻对同一个标准时间点来说,日历时间都是一样的。
clock tick 时钟计时单元(而不把它叫做时钟滴答次数),一个时钟计时单元的时间长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位。
一、C/C++ 获取时间并格式化输出
详细请参考C/C++获取时间函数。
1. 计时函数
1)clock_t clock(void);
返回从“开启这个程序进程”到“程序中调用clock()函数”时 之间的CPU时钟计时单元(clock tick)数,MSDN称挂钟时间(wall-clock),clock_t的类型定义如下,clock_t是一个long类型的数:
1 #ifndef _CLOCK_T_DEFINED 2 typedef long clock_t; 3 #define _CLOCK_T_DEFINED 4 #endif
1 //常量,表示一秒钟会有多少个时钟计时单元 2 #define CLOCKS_PER_SEC ((clock_t)1000)
2)double difftime(time_t time1, time_t time0);
只能精确到秒(并不说明该时间具有double一样的精度),这是由其传入参数决定的。
3)DWORD WINAPI GetTickCount(VOID);
在Release版本中,该函数从0开始计时,返回自设备启动后的毫秒数(不含系统暂停时间)。对于一般的实时控制,使用GetTickCount()函数就可以满足精度要求,但要进一步提高计时精度,就要采用QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 9X使用的高精度时间函数,并要求计算机从硬件上支持高精度计时器。
1 #include<winbase.h> 2 #define GetCurrentTime() GetTickCount()
1 #include<sysinfoapi.h>
2 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
3
4 __drv_preferredFunction("GetTickCount64", "GetTickCount overflows roughly every 49 days. Code that does not take that into account can loop indefinitely. GetTickCount64 operates on 64 bit values and does not have that problem")
5 WINBASEAPI 6 DWORD 7 WINAPI 8 GetTickCount( 9 VOID 10 ); 11 #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
我在具体使用时直接调用获取的是time_t/DWORD类型值不是电脑当前准确时间,而是1970年的某一个时间,所以千万不要误用。同时还应该与CTime类中的GetCurrentTime区分开来。
2. 获取当前日历时间 time_t time (time_t* timer)
1 #ifndef _TIME_T_DEFINED 2 typedef long time_t; 3 #define _TIME_T_DEFINED 4 #endif
参数及返回值类型说明:对time_t数据类型的值来说,它所表示的时间不能晚于2038年1月18日19时14分07秒,部分编译器如VC++采用了__time64_t并通过_time64()函数来获得日历时间,这样就可以通过该数据类型保存3001年1月1日0时0分0秒(不包括该时间点)之前的时间。
参数及返回值说明:C 库函数 time_t time(time_t *seconds) 返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。
3. 常用结构体tm
1 #ifndef _TM_DEFINED 2 struct tm 3 { int tm_sec; /* 秒 – 取值区间为[0,59] */ 4 int tm_min; /* 分 - 取值区间为[0,59] */ 5 int tm_hour; /* 时 - 取值区间为[0,23] */ 6 int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */ 7 int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */ 8 int tm_year; /* 年份,其值等于实际年份减去1900 */ 9 int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */ 10 int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */ 11 int tm_isdst; /* 夏令时标识符,实行夏令时,tm_isdst为正。不实行夏令时,tm_isdst为0;不了解情况时,tm_isdst()为负。*/ 12 }; 13 #define _TM_DEFINED 14 #endif
需要注意的是进行年份计算时+1900,月份计算+1,或者:
真实_year = tm_year + 1900;
真实_month = tm_mon + 1;
4. 获得时间及格式化、转换函数
1) 获得日期和时间
1 struct tm * gmtime(const time_t *timer); //将日历时间转化为世界标准时间(即格林尼治时间),并返回一个tm结构体来保存这个时间 2 struct tm * localtime(const time_t * timer); //将日历时间转换为本地时间,从1970年起始的时间戳转换为1900年起始的时间数据结构
比如现在用gmtime()函数获得的世界标准时间是2005年7月30日7点18分20秒,那么我用localtime()函数在中国地区获得的本地时间会比时间标准时间晚8个小时,即2005年7月30日15点18分20秒。
1 #include "time.h" 2 #include "stdio.h" 3 int main(void) 4 { 5 struct tm *local; 6 time_t t; 7 t=time(NULL); 8 local=localtime(&t); 9 printf("Local hour is: %d/n",local->tm_hour); 10 local=gmtime(&t); 11 printf("UTC hour is: %d/n",local->tm_hour); 12 return 0; 13 }
2) 时间格式及转换
1 char * asctime(const struct tm * timeptr); //通过tm结构来生成具有固定格式的保存时间信息的字符串(只是把tm结构对象中的各个域填到时间字符串的相应位置就行了) 2 char * ctime(const time_t *timer); //通过日历时间来生成时间字符串(需要先参照本地的时间设置,把日历时间转化为本地时间,然后再生成格式化后的字符串)
以上返回值char*格式均为星期几 月份 日期 时:分:秒年/n/0 ,例如:Wed Jan 02 02:03:55 1980/n/0.
1 time_t mktime(struct tm * timeptr); //将用tm结构表示的时间转化为日历时间
每种系统平台提供的参照时间可能不同,但这不是我们变成所关注的焦点,因为其处理细节已经被封装,只需大胆调用即可。
3) 自定义时间格式
1 size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm *timeptr ); //类似于sprintf()
参考Linux时间编程之strftime():格式化输出好帮手,其中const char* format参考如下表列出格式。
格 式 | 说 明 |
%a | 星期几的简写 |
%A | 星期几的全称 |
%b | 月分的简写 |
%B | 月份的全称 |
%c | 标准的日期的时间串 |
%C | 年份的后两位数字 |
%d | 十进制表示的每月的第几天 |
%D | 月/天/年 |
%e | 在两字符域中,十进制表示的每月的第几天 |
%F | 年-月-日 |
%g | 年份的后两位数字,使用基于周的年 |
%G | 年分,使用基于周的年 |
%h | 简写的月份名 |
%H | 24小时制的小时 |
%I | 12小时制的小时 |
%j | 十进制表示的每年的第几天 |
%m | 十进制表示的月份 |
%M | 十时制表示的分钟数 |
%n | 新行符 |
%p | 本地的AM或PM的等价显示 |
%r | 12小时的时间 |
%R | 显示小时和分钟:hh:mm |
%S | 十进制的秒数 |
%t | 水平制表符 |
%T | 显示时分秒:hh:mm:ss |
%u | 每周的第几天,星期一为第一天 (值从0到6,星期一为0) |
%U | 第年的第几周,把星期日做为第一天(值从0到53) |
%V | 每年的第几周,使用基于周的年 |
%w | 十进制表示的星期几(值从0到6,星期天为0) |
%W | 每年的第几周,把星期一做为第一天(值从0到53) |
%x | 标准的日期串 |
%X | 标准的时间串 |
%y | 不带世纪的十进制年份(值从0到99) |
%Y | 带世纪部分的十制年份 |
%z,%Z | 时区名称,如果不能得到时区名称则返回空字符 |
%% | 百分号 |
二、Windows系统获取时间
Windows关于时间的结构体如下所示。
1 typedef struct _SYSTEMTIME 2 { 3 WORD wYear ; // 年 4 WORD wMonth ; // 月 5 WORD wDayOfWeek ; // 星期,0=星期日,1=星期一... 6 WORD wDay ; // 日 7 WORD wHour ; // 时 8 WORD wMinute ; // 分 9 WORD wSecond ; // 秒 10 WORD wMilliseconds ; // 毫秒 11 } SYSTEMTIME;
1. 系统API GetSystemTime()
函数原型如下,lpSystemTime可以直接 填写 SYSTEMTIME 类型,但是 必须 要加上 &,即为指针类型值。
1 //#include<sysinfoapi.h>中声明的 2 WINBASEAPI VOID WINAPI GetSystemTime (LPSYSTEMTIME lpSystemTime);
GetSystemTime所返回的是UTC协调世界时(Coordinated Universal Time,简写作UTC,之前也被拼做Universal Time Coordinated,有时是Universal Coordinated Time)。它是由国际无线电咨询委员会定义和建议采用的,并由国际时间局(BIH)负责保持的以国际单位制(SI)秒为单位的时间标度。对与无线电规则相关的大部分实际应用而言,协调世界时(UTC)与本初子午线(经度零度)上的平均太阳时等效。该时间过去以格林威治平均时(GMT)表示。
协调世界时使用24小时制的时钟表示,但也可以被转换为12小时制的时钟(AM和PM)。UTC用于飞行和航海,它有时也被称作祖鲁。UTC使用阳历。
2. 系统API GetLocalTime()
GetLocalTime获得的时间是基于本地时间的。
1 //#include<sysinfoapi.h>中声明的 2 WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime);
如GetLocalTime获得的本地主机的时间是上午8时,当用GetSystemTime获取时,该时间是0时,注意这两个函数的区别!
3. time_t、SYSTEMTIME和tm格式相互转换
1)time_t 转 SYSTEMTIME。
1 const SYSTEMTIME Time_tToSystemTime(time_t t) 2 { 3 tm temptm; 4 localtime_s(&temptm, &t); 5 SYSTEMTIME st = { 1900 + temptm.tm_year, 6 1 + temptm.tm_mon, 7 temptm.tm_wday, 8 temptm.tm_mday, 9 temptm.tm_hour, 10 temptm.tm_min, 11 temptm.tm_sec, 12 0 }; 13 return st; 14 }
2)SYSTEMTIME 转 time_t。
1 const time_t SystemTimeToTime_t(const SYSTEMTIME& st) 2 { 3 struct tm gm = { st.wSecond, st.wMinute, st.wHour, st.wDay, st.wMonth - 1, st.wYear - 1900, st.wDayOfWeek, 0, 0 }; 4 return mktime(&gm); 5 }
三、MFC获取系统时间
CTime的静态成员函数GetCurrentTime(),获取系统当前时间。
#include <ctime>
1 // CTime类中的静态成员函数 2 CTime t = CTime::GetCurrentTime(); 3 int d = t.GetDay(); // 获得几号 4 int y = t.GetYear(); 5 int m = t.GetMonth(); 6 int h = t.GetHour(); 7 int mm = t.GetMinute(); 8 int s = t.GetSecond(); 9 int w = t.GetDayOfWeek(); // 获取星期几,1为星期天,7为星期六 10 CString strTime = t.Format(_T("%Y-%m-%d %H:%M:%S")); 11 12 // 如果想计算两端时间的差值,可以使用CTimeSpan类 13 CTime t1(1999, 3, 19, 22, 15, 0); 14 CTimeSpan span = t - t1; 15 int iDay = span.GetDays(); // 获取这段间隔共有多少天 16 int iHour = span.GetTotalHours(); // 共有多少小时 17 int iMin = span.GetTotalMinutes(); // 共有多少分钟 18 int iSec = span.GetTotalSeconds(); // 共有多少秒 19 20 SYSTEMTIME sysTm, LocTm; 21 GetSystemTime(&sysTm); // 获取格林威治标准时间,与北京时间相差8小时 22 GetLocalTime(&LocTm); // 获取本时区时间,中国即东八区北京时间 23 // 获取当前时间与1970年1月1日0点0时0分的秒数差 24 CTime t2 = CTime::GetCurrentTime();
--------------待完善--------------