时间时区概念及常用时间函数

时区,为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议 )上,规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为中时区(零时区)、东1-12区,西1-12区,每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。


硬件时钟(又称实时时钟,也就是RTC),实时时钟为操作系统提供了一个可靠的时间,并且在断电的情况下,RTC实时时钟也可以通过电池供电,一直运行下去,用来保存和同步计算机操作系统时间。RTC通过STRB/LDRB这两个ARM指令向CPU传送8位数据(BCD码)。数据包括秒,分,小时,星期,天,月和年。RTC实时时钟依靠一个外部的石英晶体,产生周期性的脉冲信号,每一个信号到来时,计数器就加1,通过这种方式,完成计时功能。


系统时钟,操作系统认知的时间,包括时区信息和UTC时间(unix时戳均使用1970年1月1日0时0分0秒到目前的UTC秒数)两部分,时区信息保存在/etc/localtime文件中,一般由/usr/share/zoneinfo/目录下的时区文件拷贝或链接而来(该目录包含所有支持的时区文件,修改时区其实是替换/etc/localtime文件,而不是直接修改该文件内容)。UTC时间是UNIX系统所使用的标准时间,不同地区的人使用时显示的本地时间由UTC+时区而来(也可以说所有Unix/linux操作系统的系统时间都相同,1970年1月1日0时0分0秒到目前的UTC秒数)。


了解以上概念我们知道,计算机系统一般包括三个重要的时间(也是容易搞混的时间,通常我们所说的计算机时间应该指的是本地时间,用户在第一次使用设备时需要选择时所在区),分别为硬件rtc时间,系统utc时间和本地local时间。三者有以下关系:

硬件rtc时间是在关机或掉电状态能够继续保存的,所以为主导地位,其他时间都可以由该时间计算得来(系统时间在操作系统运行起来后被rtc同步),rtc保存的时间可以有两种,一是utc时间,二是local时间,以东八区为例:

当rtc时间为utc时间:系统utc时间 = rtc时间, 本地local时间 = rtc时间 + 8小时;

当rtc时间为local时间:系统utc时间 = rtc时间 - 8小时, 本地local时间 = rtc时间 ;

两种设置都可以,没有明确规定,不过一般Windows和Linux都默认rtc保存local本地时间。


linux时间结构体定义:

struct tm
{
     int    tm_sec;
     int    tm_min;
     int    tm_hour;
     int    tm_mday;
     int    tm_mon;
     int    tm_year;
     int    tm_wday;
     int    tm_yday;
     int    tm_isdst;
};
int    tm_sec   代表目前秒数,正常范围为0-59,但允许至61秒
int    tm_min   代表目前分数,范围0-59
int    tm_hour   从午夜算起的时数,范围为0-23
int    tm_mday   目前月份的日数,范围01-31
int    tm_mon   代表目前月份,从一月算起,范围从0-11
int    tm_year   从1900年算起至今的年数
int    tm_wday   一星期的日数,从星期一算起,范围为0-6
int    tm_yday   从今年1月1日算起至今的天数,范围为0-365
int    tm_isdst   日光节约时间的旗标


timeval结构定义为:
struct    timeval

{
     long tv_sec;     /*秒*/
     long tv_usec;     /*微秒*/
};
timezone结构定义为:
struct    timezone

{
     int tz_minuteswest;    /*和Greenwich 时间差了多少分钟*/
     int tz_dsttime;    /*日光节约时间的状态*/
};


linux常用时间函数介绍:


1、time(取得当前时间UTC秒数,无时区转换)

#include<time.h>

time_t time(time_t *t);

这个函数应该算是最常用函数之一,返回UTC标准秒数,没有时区转换,在伦敦和上海同时调用这个函数返回值相同。


2、gmtime(获取当前时间结构,UTC时间,无时区转换)

#include<time.h>

struct tm *gmtime(const time_t *timep)

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

这两个函数意思一样,将timep这个秒数转换成以UTC时区为标准的年月日时分秒时间。gmtime_r是线程安全的,推荐使用这个。gmtime返回的是一个structtm*,这个指针指向一个静态的内存,这块区域是会经常被改动的。你刚调用gmtime(),执行了其他几条命令,然后想使用刚才gmtime()得到struct  tm,会发现内容不对了,所以很危险,使用gmtime_r后就没有问题,gmtime_r会将结果保存到你传入的内存中。


3、localtime(获取当前时间结构,本地时间,有时区转换)

#include<time.h>

struct tm *localtime(const time_t * timep);

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

这两个函数意思也一样,会根据时区信息得到本地时间,同样建议使用localtime_r版本。


4、mktime(将时间结构转换为UTC秒数,有时区转换)

#include<time.h>

time_t mktime(struct tm *tm);

将已经根据时区信息计算好的structtm转换成time_t的秒数。计算出的秒数是以UTC时间为标准的,跟调用time()得到的秒数是同一个概念。


5、gettimeofday(获取当前时间,UTC时间,精度微妙,无时区转换)

#include <sys/time.h>
#include <unistd.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);

这个timeval是相对time_t更精确的时间,包含了微妙数。tv_usec最大为999999,再加1则为1秒,超过1秒就进位到tv_sec。timezone一般传入NULL,linux没有处理timezone中的tz_dsttime信息,所以在编程时不要从这里获取时区信息。

6、ctime(将时间转换为本地时间字符串, 有时区转换)

#include<time.h>

char *ctime(const time_t *timep);

7、asctime(将时间转换为字符串, 无时区转换)

#include<time.h>

char *ctime(const time_t *timep);

char * asctime(const struct tm * timeptr);


代码示例:

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

int main(int argc, char* argv[])
{
	time_t timep;
	time(&timep);//获取UTC秒数

	//ctime转换为本地时间字符串形式,有时区转换
	printf("timep = %ld, local time = %s", timep, ctime(&timep));

	struct timeval tv;
	gettimeofday(&tv, NULL);//获取微秒精度时间结构,UTC无时区转换
	printf("tv.sec = %ld, tv.usec = %ld\n", tv.tv_sec, tv.tv_usec);

	struct tm result_gmtime, result_localtime;
	gmtime_r(&timep, &result_gmtime);//获取UTC时间结构,无时区转换
	localtime_r(&timep, &result_localtime);//获取本地时间结构,有时区转换

	//时间结构转换为字符串显示,无时区转换
	printf("gmtime_r = %s", asctime(&result_gmtime));
	printf("localtime_r = %s", asctime(&result_localtime));

	//mktime将本地时间转换为UTC秒数,有时区转换
	printf("mktime localtime to utc = %ld\n", mktime(&result_localtime));
	//错误值示范,本身是UTC,再减时区结果是错误的
	printf("mktime localtime to utc = %ld\n", mktime(&result_gmtime));
	
	return 0;
}

执行结果:

timep = 1471929196, local time = Tue Aug 23 13:13:16 2016

tv.sec = 1471929196, tv.usec = 146952

gmtime_r = Tue Aug 23 05:13:16 2016

localtime_r = Tue Aug 23 13:13:16 2016

mktime localtime to utc = 1471929196

mktime localtime to utc = 1471900396

可见最后一行时间打印是个错误值。
原文地址:https://www.cnblogs.com/yangxx/p/6702003.html