基本概念

UTC全称为 Coordinated Universal Time 世界协调时,是一个时间体系。GMT全称为Greenwich Mean Time格林尼治平太阳时间,可以指一个时区。

GMT的计算是基于地球自转,一个周期约为86,400.002秒,它随着地球自转周期的变化而变化。UTC基于SI标准的原子时间,一个周期为精确的86,400.00秒,由于潮汐力等因素,地球自转周期在慢慢变长,当差别到±0.9秒时,就把协调世界时向前拨1秒或向后拨1秒这样就和GMT时间(地球自转)相同了。

东八区表示为 UTC+8 全球通用,英联邦国家则更倾向于使用 GMT+8。因此,UTC更为标准,在科学和工程中换算时间也是用UTC系统。

Epoch 指 UTC 时间从 1970 一月一日 0 时 0 分 0秒 开始的一个整数值

基本类型

C 语言使用下面五个类型来表示时间,time_t 和 clock_t 通常是一个整形来实现这个类型

  1. time_t // 表示从 Epoch 开始计算的时间
  2. clock_t // 进程消耗处理器的时间
  3. struct tm {
  4. int tm_sec; /* seconds after the minute [0-60] */
  5. int tm_min; /* minutes after the hour [0-59] */
  6. int tm_hour; /* hours since midnight [0-23] */
  7. int tm_mday; /* day of the month [1-31] */
  8. int tm_mon; /* months since January [0-11] */
  9. int tm_year; /* years since 1900 */
  10. int tm_wday; /* days since Sunday [0-6] */
  11. int tm_yday; /* days since January 1 [0-365] */
  12. int tm_isdst; /* Daylight Savings Time flag */
  13. long tm_gmtoff; /* offset from UTC in seconds */
  14. char *tm_zone; /* timezone abbreviation */
  15. }; // 来表示日期
  16. struct timespec {
  17. __darwin_time_t tv_sec;
  18. long tv_nsec;
  19. }; // 秒和纳秒 C11/MSVC
  20. struct timeb {
  21. time_t time; /* [XSI] Seconds since the Epoch */
  22. unsigned short millitm; /* [XSI] Milliseconds since the Epoch */
  23. short timezone; /* [XSI] Minutes west of CUT */
  24. short dstflag; /* [XSI] non-zero if DST in effect */
  25. }; // 获取毫秒
  26. struct timeval {
  27. __darwin_time_t tv_sec; /* seconds */
  28. __darwin_suseconds_t tv_usec; /* and microseconds */
  29. }; // 秒和微秒 UNIX 系统下

获取系统时间

  1. #include <time.h>
  2. int main() {
  3. time_t current_t;
  4. time(&current_t);
  5. }

time 也可以使用返回值,传入指针比较块,time 函数返回的是秒数不精确,通常用来获取日历时间转化为 tm 结构体。

  1. #include <sys/timeb.h>
  2. int main() {
  3. struct timeb current_t;
  4. ftime(&current_t);
  5. }

timeb 有用的字段就是 time 和 millitm

  1. #include <time.h>
  2. int main() {
  3. struct timeval current_t;
  4. gettimeofday(&current_t, NULL);
  5. }

timeval 和 gettimeofday 在 UNIX 系统下生效

  1. #include <time.h>
  2. int main() {
  3. struct timespec currrnt_t;
  4. timespec_get(&currrnt_t, TIME_UTC);
  5. }

timespec 在 C11 和 windows 下使用

本地时间

  1. #include <time.h>
  2. int main() {
  3. time_t current_time;
  4. time(&current_time);
  5. struct tm * cal_t = localtime(&current_time);
  6. }
  7. time_t current_time_1 = mktime(cal_t);

mktime 用来反过来解析 tm 结构体,mktime 不仅会将结构体进行转换,而且会进行属性检查,例如 70 秒会转化为 1 分 10 秒。

time 将 time_t 根据电脑所在的时区转化成,gmttime 时间根据 time_t 转化成零时区的时间。

格式化时间

  1. time_t current_time;
  2. time(&current_time);
  3. struct tm * cal_t = localtime(&current_time);
  4. asctime(cal_t);
  5. ctime(&current_time);
  1. char current_time[20];
  2. strftime(current_time, %Y-%m-%d %H %M %S, cal_t);
  3. // 等价于
  4. strftime(current_time, %Y %T, cal_t);

C 语言标准库不支持毫秒但是我们可以追加上去,因为毫秒只是数字罢了

解析时间

将 strftime 处理出来的字符串解析成 tm 结构体,strptime 并不是标准库的函数是 poix 对于 c 标准的扩展,需要定义 _XOPEN_SOURCE 宏来开启

  1. struct tm * cal_t;
  2. char * unparsed_string = strptime(time, "%F %T", &cal_t);

可以使用返回值来解析毫秒数,返回值返回的是没有解析的字符串,也可以使用 sscanf 来解析 2020-11-10 23:10:9 这样的字符串

  1. struct tm * cal_t;
  2. char *time = "2020-11-10 23:10:09";
  3. sscanf(time, "%4d-%2d-%2d %2d:%2d:%2d", &cal_t.tm_year, ...); // 省略

sscanf()会将参数str 的字符串根据参数format(格式化字符串)来转换并格式化数据(格式化字符串请参考scanf()), 转换后的结果存于对应的变量中。

程序时间差

  1. cloct_t start_time = clock();
  2. // do something
  3. cloct_t end_time = clock();
  4. CLOCKS_PRE_SEC

clock 函数返回一个整数,CLOCKS_PRE_SEC 定义了每秒有多少时钟,那么使用 clock_t 除以 CLOCKS_PRE_SEC 就得到了秒数,最好在除之前加一个 1.0 转换成浮点数。

clock 更能反应程序运行时间,比 time 更准确,因为 cpu 会同时执行很多程序,会并行执行,time 只反应真实世界经历的时间。