测试环境:vmware 7 + Redhat5.5,系统时间使用UTC,时区为上海。

1、函数功能介绍

使用man gmtime或man localtime都可以的得到这几个函数的介绍。原型如下:

struct tm *gmtime(const time_t *timep);

struct tm *gmtime_r(const time_t *timep, struct tm *result);

struct tm *localtime(const time_t *timep);

struct tm *localtime_r(const time_t *timep, struct tm *result);

man手册中对它们的解释如下:

The gmtime() function converts the calendar time timep to broken-down time representation, expressed in Coordinated Universal Time (UTC). It may return NULL when the year does not fit into an integer. The return value points to a statically allocated struct which might be overwritten  by subsequent calls to any of the date and time functions. The gmtime_r() function does the same, but stores the data in a user-supplied struct.

The localtime() function converts the calendar time timep to broken-time representation, expressed relative to the user's specified time zone. The function acts as if it called tzset(3) and sets the external variables tzname with information about the current time zone, timezone with  the difference between Coordinated Universal Time (UTC) and local standard time in seconds, and daylight to a non-zero value if daylight savings time rules apply during some part of the year.  The return value points to a statically allocated struct which might be overwritten by subsequent calls to any of the date and time functions. The localtime_r() function does the same, but stores  the data in a user-supplied struct. It need not set tzname。

翻译如下:

gmtime() 函数将日历时间timep转换为用UTC时间表示的时间。它可能返回NULL,比如年份不能放到一个整数中。返回值指向一个静态分配的结构,该结构可能会被接下来的任何日期和时间函数调用覆盖。gmtime_r()函数功能与此相同,但是它可以将数据存储到用户提供的结构体中。

localtime() 函数将日历时间timep转换为用户指定的时区的时间。这个函数的行为好像是它调用了tzset(3) 并且将外部变量tzname设置为当前时区的信息,将timezone设为UTC和本地标准时间的差值,并且,如果在一年的部分时间使用日光节约规则时将daylight设置为非空值。返回值指向一个静态分配的结构,该结构可能会被接下来的任何日期和时间函数调用覆盖。localtime_r()函数功能与此相同,但是它可以将数据存储到用户提供的结构体中。它不需要设置tzname。

2、功能测试

程序一:

#include <stdio.h>

#include <time.h>

int main()

{

time_t cur_time=time(NULL);

if( cur_time < 0 )

{

perror("time");

return -1;

}

struct tm utc_tm;;

if( NULL == gmtime_r( &cur_time, &utc_tm ) )

{

perror("gmtime" );

return -1;

}

struct tm local_tm;

if( NULL == localtime_r( &cur_time, &local_tm ) )

{

perror("localtime" );

return -1;

}

printf("UTC = %s", asctime(&utc_tm) );

printf("LOC = %s", asctime(&local_tm) );

printf("LOC = %s", ctime(&cur_time) );

return 0;

}

程序输出:

UTC = Thu Oct 27 09:16:10 2011

LOC = Thu Oct 27 17:16:10 2011

LOC = Thu Oct 27 17:16:10 2011

由于系统时间使用了UTC,可以看到“本地时间= UTC时间 + 8”,输出正确。

程序二:

#include <stdio.h>

#include <time.h>

int main()

{

time_t cur_time=time(NULL);

if( cur_time < 0 )

{

perror("time");

return -1;

}

struct tm *utc_tm = gmtime( &cur_time );

if( NULL == utc_tm )

{

perror("gmtime" );

return -1;

}

printf("UTC = %s", asctime(utc_tm) );

struct tm *local_tm = localtime( &cur_time );

if( NULL == local_tm )

{

perror("localtime" );

return -1;

}

printf("LOC = %s", asctime(local_tm) );

printf("LOC = %s", ctime(&cur_time) );

return 0;

}

程序输出:

UTC = Thu Oct 27 09:20:45 2011

LOC = Thu Oct 27 17:20:45 2011

LOC = Thu Oct 27 17:20:45 2011

同样是正确的。

程序三:

#include <stdio.h>

#include <time.h>

int main()

{

time_t cur_time=time(NULL);

if( cur_time < 0 )

{

perror("time");

return -1;

}

struct tm *utc_tm = gmtime( &cur_time );

if( NULL == utc_tm )

{

perror("gmtime" );

return -1;

}

struct tm *local_tm = localtime( &cur_time );

if( NULL == local_tm )

{

perror("localtime" );

return -1;

}

printf("UTC = %s", asctime(utc_tm) );

printf("LOC = %s", asctime(local_tm) );

printf("LOC = %s", ctime(&cur_time) );

return 0;

}

程序输出:

UTC = Thu Oct 27 17:21:59 2011

LOC = Thu Oct 27 17:21:59 2011

LOC = Thu Oct 27 17:21:59 2011

这程序输出有错,UTC时间和本地时间相同了,这应该就是由于man文档中描述的“可能会被接下来的任何日期和时间函数调用覆盖”造成的。为验证这个设想,使用程序四:

程序四:

#include <stdio.h>

#include <time.h>

int main()

{

time_t cur_time=time(NULL);

if( cur_time < 0 )

{

perror("time");

return -1;

}

struct tm *local_tm = localtime( &cur_time );

if( NULL == local_tm )

{

perror("localtime" );

return -1;

}

struct tm *utc_tm = gmtime( &cur_time );

if( NULL == utc_tm )

{

perror("gmtime" );

return -1;

}

printf("UTC = %s", asctime(utc_tm) );

printf("LOC = %s", asctime(local_tm) );

printf("LOC = %s", ctime(&cur_time) );

return 0;

}

程序输出:

UTC = Thu Oct 27 09:24:23 2011

LOC = Thu Oct 27 09:24:23 2011

LOC = Thu Oct 27 17:24:23 2011

验证了该设想。

3、总结

使用gmtime和localtime后要立即处理结果,否则返回的指针指向的内容可能会被覆盖,一个好的方法是使用gmtime_r和localtime_r,由于使用了用户分配的内存,这两个函数是不会出错的。

1 #include <cstdlib>

2 #include <iostream>

3 #include <time.h>

4 #include <stdio.h>

5

using namespace std;

7

int main(int argc, char *argv[])

9 {

10     time_t tNow =time(NULL);

11     time_t tEnd = tNow + 1800;

12     //注意下面两行的区别

13     struct tm* ptm = localtime(&tNow);

14     struct tm* ptmEnd = localtime(&tEnd);

15

16     char szTmp[50] = {0};

17     strftime(szTmp,50,"%H:%M:%S",ptm);

18     char szEnd[50] = {0};

19     strftime(szEnd,50,"%H:%M:%S",ptmEnd);

20

21

22     printf("%s /n",szTmp);

23     printf("%s /n",szEnd);

24

25

26     system("PAUSE");

27     return EXIT_SUCCESS;

28 }

最后出来的结果是:

21:18:39

21:18:39

和最初想法不一致。

查阅localtime的文档,发现这段话:

This structure is statically allocated and shared by the functions gmtime and localtime. Each time either one of these functions is called the content of this structure is overwritten.

也就是说每次只能同时使用localtime()函数一次,要不就会被重写!

The localtime() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe.

因此localtime()不是可重入的。同时libc里提供了一个可重入版的函数localtime_r();

Unlike localtime(), the reentrant version is not required to set tzname。

修改程序:

[c-sharp] view plaincopy

29 #include <cstdlib>

30 #include <iostream>

31 #include <time.h>

32 #include <stdio.h>

33

34 using namespace std;

35

36 int main(int argc, char *argv[])

37 {

38     time_t tNow =time(NULL);

39     time_t tEnd = tNow + 1800;

40

41     //在这里修改程序

42     //struct tm* ptm = localtime(&tNow);

43     //struct tm* ptmEnd = localtime(&tEnd);

44     struct tm ptm = { 0 };

45     struct tm ptmEnd = { 0 };

46     localtime_r(&tNow, &ptm);

47     localtime_r(&tEnd, &ptmEnd);

48

49     char szTmp[50] = {0};

50     strftime(szTmp,50,"%H:%M:%S",&ptm);

51     char szEnd[50] = {0};

52     strftime(szEnd,50,"%H:%M:%S",&ptmEnd);

53     printf("%s /n",szTmp);

54     printf("%s /n",szEnd);

55

56

57     system("PAUSE");

58     return EXIT_SUCCESS;

59 }

最后出来的结果是:

10:29:06 
10:59:06

在写代码的时候,经常会用到读取系统时间的函数。很多人都会调用localtime函数来将时间转换本地时间,但是大家往往会忽略了一点,localtime函数不是线程安全的。如果在多线程里调用localtime函数,很可能会出现问题。

多线程应用里面,应该用localtime_r函数替代localtime函数,因为localtime_r是线程安全的。

struct tm *localtime(const time_t *clock);

struct tm* localtime_r( const time_t* timer, struct tm* result )

二十 关于gmtime、gmtime_r、localtime、localtime_r相关推荐

  1. python爬虫影评_Python爬虫(二十)_动态爬取影评信息

    本案例介绍从JavaScript中采集加载的数据.更多内容请参考:Python学习指南 #-*- coding:utf-8 -*- import requests import re import t ...

  2. Ubuntu16.04 装机之后要做的二十件事

    Ubuntu装机之后要做的二十件事 用ubuntu做东西很久了,总结了一些教程,一直想整理一下,确实是没有时间,这下简单的整理了一下,大家可以看看,具体的软件安装包已经推到了本人的百度云帐号下面了,需 ...

  3. 2021年大数据Hadoop(二十九):​​​​​​​关于YARN常用参数设置

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 关于yarn常用参数设置 设置container分配最小内 ...

  4. 2021年大数据Hadoop(二十六):YARN三大组件介绍

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 Yarn三大组件介绍 ResourceManager No ...

  5. 2021年大数据Hadoop(二十五):YARN通俗介绍和基本架构

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 YARN通俗介绍和基本架构 Yarn通俗介绍 Yarn基本 ...

  6. 2021年大数据Hadoop(二十二):MapReduce的自定义分组

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 MapReduce的自定义分组 需求 分析 实现 第一步: ...

  7. 二十岁出头的时候上,你一无所有,你拥有一切

    一篇治愈系的励志文,分享给大家~ (一)嘴上说说的人生 那年我在离家的时候一个劲地往自己的硬盘里塞<灌篮高手>,我妈一副嗤之以鼻的表情看着我,似乎是在说:"这么大的人了居然还这么 ...

  8. 算法系列之二十:计算中国农历(二)

    (接上篇) 所谓的"天文算法",就是利用经典力学定律推导行星运转轨道,对任意时刻的行星位置进行精确计算,从而获得某种天文现象发生时的时间,比如日月合朔这一天文现象就是太阳和月亮的地 ...

  9. Silverlight+WCF 新手实例 象棋 主界面-实时聊天区(二十五)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三) 本节连着Silverlight+WC ...

最新文章

  1. python字典操作添加_Python字典常见操作实例小结【定义、添加、删除、遍历】
  2. 命令行mvn打包的时候报错:No compiler is provided in this environment. Perhaps you are running on a JRE
  3. python 对象转dict_如何将python dict对象转换为java等效对象?
  4. C++判断文件夹是否存在
  5. hann function
  6. flask连接mysql数据库_Flask与Mysql数据库建立连接
  7. 爬虫-----自定义框架
  8. uni-app h5 分享好友与朋友圈等功能
  9. 灰鸽子病毒——网络神偷之后应用最广的反弹端口***
  10. Win7edge浏览器看视频黑屏怎么解决?
  11. TextField 、 FTE、 TLF 的使用情景和简单说明
  12. 我国首部《密码法》来了!资深律师跟我说,他是这么看的...
  13. 巴西游戏出海攻略,优质游戏出海市场
  14. 目前住院病人主要由护士护理,这样做不仅需要大量护士
  15. 【金融风控-贷款违约预测】数据挖掘学习:5.模型融合
  16. 【gis技术】web墨卡托投影和经纬度直投的差别
  17. QCC305x系列开发教程(入门篇)之1.2-安装开发中需要配套软件
  18. OC底层探索(七) cache_t分析
  19. 上海万国驾校 科目二知识点归纳
  20. 企业如何利用免费ERP系统进行内部控制

热门文章

  1. 富人越富,穷人越穷,我为什么反对PoS
  2. oracle基本操作手册
  3. 2021年广东省雷州市客路镇高考成绩查询,雷州市客路镇隆重召开庆祝第31个教师节暨表彰大会...
  4. One-move Checkmate (ZOJ 1598)
  5. 在ASP.NET中使用ListView控件对数据进行显示、分页和排序
  6. 我分析了 6.5W 字的歌词,看到了这样的周杰伦
  7. CODESYS (V3.5 SP12 Patch)程序开发前的配置及简单应用 第 1 篇(长沙赛搏机器智能MIC7001总线控制器+松下A6BE总线驱动器)
  8. Linux系统中进程的查看及控制
  9. MAX8722 CCFL背光控制器
  10. 如何用画图框住所选内容_我们知道您的住所-在线隐私之死