之前在https://blog.csdn.net/fengbingchun/article/details/107023645 中介绍过gmtime和localtime的区别,这里介绍下日期与Unix时间戳之间转换的实现,其中也会用到这两个函数。
Unix时间戳(Unix timestamp):是一种时间表示方式,定义为从格林威治时间(Greenwich Mean Time, GMT)1970年01月01日00时00分00秒起至现在的总秒数。如果操作系统使用32位二进制数字表示时间,则此类系统的Unix时间戳最多可以使用到格林威治时间2038年01月19日03时14分07秒(二进制: 01111111 11111111 11111111 11111111)。
时区:地球上的区域使用同一个时间定义。由于世界各国家与地区经度不同,地方时也有所不同,因此会划分为不同的时区。正式的时区划分包括24个时区,每一时区由一个英文字母表示。每差一个时区,区时相差一个小时,相差多少个时区,就相差多少个小时。为了照顾到各地区的使用方便,又使其它地方的人容易将本地的时间换算到别的地方时间上去。有关国际会议决定将地球表面按经线从东到西,划成一个个区域,并且规定相邻区域的时间相差1小时。在同一区域内的东端和西端的人看到太阳升起的时间最多相差不过1小时。当人们跨过一个区域,就将自己的时钟校正1小时(向西减1小时,向东加1小时),跨过几个区域就加或减几小时。例如,中国东8区的时间总比泰国东7区的时间早1小时,而比日本东9区的时间晚1小时。因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致。凡向西走,每过一个时区,就要把表拨慢1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表拨快1小时(比如1点拨到2点)。并且规定英国(格林尼治天文台旧址)为本初子午线,即零度经线。
本地时间(locale time):可由localtime函数获得,在中国为UTC+08:00,或称北京时间或东八时区。
协调世界时(Coordinated Universal Time, UTC):或世界标准时间,UTC的表示方式为:年、月、日、时、分、秒,均用数字表示。可以认为格林威治时间就是协调世界时(GMT=UTC),格林威治时间和UTC时间均有秒数来计算。
C语言中一些常用的函数:
(1).time_t:时间类型,基础算术类型的别名,能够表示时间,通常是一个大整数值,该整数值表示自UTC时间1970年1月1日00:00:00时起经过的秒数(即Unix时间戳)。
(2).struct tm:时间结构体,包含日历日期和时间的结构体,该结构体包含int类型的9个成员。
(3).time:获取当前时间,返回time_t,如果参数不是空指针,还将此值设置为参数指向的对象。返回的值通常代表自1970年1月1日00:00:00时起经过的秒数(即本地时间的Unix时间戳)。
(4).ctime:将time_t转换为字符串,返回char*。此函数等价于asctime(localtime(time_t))。
(5).asctime:将tm结构体转换为字符串,返回char*。
(6).strftime:将tm结构体转换为字符串,返回size_t。
(7).localtime:将time_t转换为本地时间,返回tm结构体。
(8).gmtime:将time_t转换为UTC时间,返回tm结构体。
(9).difftime:计算两个time_t之间的时间差(以秒为单位),返回double。
(10).mktime:将tm结构体转换为time_t,返回类型为time_t,本地时间,如无法表示日历时间,则返回值为-1。
以上函数用法的测试代码段如下:
void test_time() { time_t rawtime = time(nullptr); //time_t rawtime; time(&rawtime); struct tm* timeinfo = localtime(&rawtime); fprintf(stdout, "The current local date/time is: %s", asctime(timeinfo)); timeinfo = gmtime(&rawtime); fprintf(stdout, "The current utc date/time is: %s", asctime(timeinfo)); fprintf(stdout, "The current local date/time is: %s", ctime(&rawtime)); timeinfo = localtime(&rawtime); timeinfo->tm_hour = timeinfo->tm_min = timeinfo->tm_sec = timeinfo->tm_mon = 0; timeinfo->tm_mday = 1; fprintf(stdout, "%.f seconds since new year in the current timezone\n", difftime(rawtime, mktime(timeinfo))); timeinfo = localtime(&rawtime); char buffer[64]; strftime(buffer, 64, "Now it's %I:%M%p", timeinfo); fprintf(stdout, "buffer: %s\n", buffer); }
执行结果如下:
下面测试代码段是本地时间的日期与时间戳之间的转换:可通过localtime和mktime函数实现
void test_date_to_timestamp_local() { // timestamp --> date time_t timestamp = time(nullptr); struct tm* timeinfo = localtime(×tamp); int year = timeinfo->tm_year + 1900; // years since 1900 int month = timeinfo->tm_mon + 1; // monthes since January - [0, 11] int day = timeinfo->tm_mday; int date = year * 10000 + month * 100 + day; int hour = timeinfo->tm_hour; int minute = timeinfo->tm_min; int second = timeinfo->tm_sec; fprintf(stdout, "timestamp: %ld, date: %d %.2d:%.2d:%.2d\n", timestamp, date, hour, minute, second); // date --> timestamp int date2 = 20211122; struct tm timeinfo2; memset(&timeinfo2, 0, sizeof(struct tm)); timeinfo2.tm_year = date2 / 10000 - 1900; timeinfo2.tm_mon = date2 % 10000 / 100 - 1; timeinfo2.tm_mday = date2 % 100; time_t timestamp2 = mktime(&timeinfo2); fprintf(stdout, "date2: %d, timestamp2: %ld\n", date2, timestamp2); }
执行结果如下:
下面测试代码段是UTC的日期与时间戳之间的转换:Linux下通过gmtime和timegm函数,Windows下通过gmtime和_mkgmtime函数。
#ifdef _MSC_VER #define timegm _mkgmtime #endif void test_date_to_timestamp_utc() { // timestamp --> date time_t timestamp = 86470; // 1day = 24 * 60 * 60 = 86400 struct tm* timeinfo = gmtime(×tamp); int year = timeinfo->tm_year + 1900; // years since 1900 int month = timeinfo->tm_mon + 1; // monthes since January - [0, 11] int day = timeinfo->tm_mday; int date = year * 10000 + month * 100 + day; int hour = timeinfo->tm_hour; int minute = timeinfo->tm_min; int second = timeinfo->tm_sec; fprintf(stdout, "timestamp: %ld, date: %d %.2d:%.2d:%.2d\n", timestamp, date, hour, minute, second); // date --> timestamp int date2 = 19700102; struct tm timeinfo2; memset(&timeinfo2, 0, sizeof(struct tm)); timeinfo2.tm_year = date2 / 10000 - 1900; timeinfo2.tm_mon = date2 % 10000 / 100 - 1; timeinfo2.tm_mday = date2 % 100; time_t timestamp2 = timegm(&timeinfo2); fprintf(stdout, "date2: %d, timestamp2: %ld\n", date2, timestamp2); }
执行结果如下:
GitHub:https://github.com/fengbingchun/Messy_Test