Linux系统编程一:时间和延时、gmtime和localtime函数返回相同

1. 概述

前面的几篇文章Linux学习笔记一到七,主要是开发环境的搭建,都是一些准备工作。从本篇文章开始,将学习Linux系统编程。

目前我的理解,基于Linux开发,大体上可分为系统(应用)、驱动、内核三个方向,难度依次加大。从系统编程开始,除了个别需要操作硬件外设的部分,绝大多数如进程、线程、TCP,在PC端完全能够运行调试。环境相对简单,理解起来也更容易,先对Linux有一个基本的印象。

打算按照自己的思路进行,不面面俱到的罗列知识点,而是每篇都做一个小实验。先从最简单的开始,从最快上手做出东西的角度来学习。

2. 延时函数

在单片机编程时,使用软件延时常通过while循环来实现。而Linux系统编程则不再需要自己实现,延时函数有两个:sleep和usleep,前者是秒级,后者是微秒级。函数原型为:

#include <unistd.h>

unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);

简单测试下延时效果,可以这样:

 while(i--) {
        sleep(2);
        printf("sleep 2\n");
        usleep(1000000);
        printf("usleep 1000000\n");
    }

可以在终端看到sleep 2和usleep 1000000交替打印:
在这里插入图片描述
但是我们并不知道时间是否准确,因此再增加系统时间的获取。

3. 当前时间

时间获取分为两步:调用和转换。

3.1 时间调用函数

通过时间调用函数time可以取得当前系统时间,其函数原型为:

#include <time.h>
time_t time(time_t *t)

得到的time_t类型时间值,实际是一个long型。它是一个机器日历时间,对于Linux来说也就是UNIX 纪元时间。
Unix time 是指从 1970 年 1 月 1 日 00:00:00 UTC 开始所经过的秒数。
根据传入参数是否为NULL,这个函数有两种使用方式:

time_t tiemp;

time(&timep);
timep = time(NULL);

在上面延时函数的基础上略作修改,以查看time函数的作用:

    while(i--) {
        sleep(2);
        time(&timep);
        printf("sleep 2:UTC time: 0x08x\n", timep);
        usleep(1000000);
        timep = time(NULL);
        printf("usleep 1000000:UTC time: 0x08x\n", timep);
    }

运行结果如下:
在这里插入图片描述
可以看到:经过2秒延时,原本的unix时间0x60c80766增加2变为0x60c80768;再经过1000000微妙,也就是1秒延时,Unix时间又增加1变为0x60c80769。与预期完全相符。
这个unix时间一大长串数字,显然还需要转换为直观易懂的时间格式,比如我们常说的某年某月的某一天。

3.2 时间转换函数

时间转换函数有四个:

char *ctime(const time_t *timep);   //将时间转化为字符串格式。
struct tm *gmtime(const time_t *timep); //将时间转化为格林威治时间
struct tm *localtime(const time_t *clock);  //将时间转化为本地时间。
char *asctime(const struct tm *tm); //将时间转换为字符格式

其中,前三个函数是直接对3.1节获取到的时间进行处理,而后面三个函数都涉及一个tm结构体,结构体内包含了我们惯用的年月日时分秒:

struct tm{
    int tm_sec; //秒 – 取值区间为[0,59]。
    int tm_min; //分 - 取值区间为[0,59]。
    int tm_hour; //时 - 取值区间为[0,23]。
    int tm_mday;//一个月中的日期 - 取值区间为[1,31]。
    int tm_mon;//月份(从一月开始,0 代表一月) - 取值区间为[0,11]。
    int tm_year;//年份,其值等于实际年份减去 1900。
    int tm_wday;//星期 – 取值区间为[0,6],其中 0 代表星期天,1 代表星期一,以此类推 。
    int tm_yday;//从每年的 1 月 1 日开始的天数 – 取值区间为[0,365],其中 0 代表 1 月 1 日,1 代表 1 月 2 日,以此类推。
    int tm_isdst; //夏令时标识符,实行夏令时的时候,tm_isdst 为正。不实行夏令时的进候,tm_isdst 为 0;不了解情况时,tm_isdst()为负。

对3.1小节代码进行修改:

    while(i--) {
		sleep(2);
		time(&timep);
        printf("sleep 2--UTC time: 0x%08x\n", timep);
		printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出
		
		t_GTM = gmtime(&timep);
		t_local = localtime(&timep);
		printf("sleep 2--GTMtime is %s", asctime(t_GTM));	
		printf("sleep 2--localtime is %s", asctime(t_local));	

		printf("sleep 2--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出
		printf("sleep 2--localtime current hour is %d\n", t_local->tm_hour);	
		
        usleep(1000000);
        timep = time(NULL);
        printf("usleep 1000000--UTC time: 0x%08x\n", timep);
		printf("usleep 1000000--ctime is %s", ctime(&timep));	//字符串输出
		
		t_GTM = gmtime(&timep);
		t_local = localtime(&timep);
		printf("usleep 1000000--GTMtime is %s", asctime(t_GTM));	
		printf("usleep 1000000--localtime is %s", asctime(t_local));	

		printf("usleep 1000000--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出	
		printf("usleep 1000000--localtime current hour is %d\n", t_local->tm_hour);
    }

查看打印结果:
在这里插入图片描述
这里格林威治时间和本地时间一样呢?

4. gmtime和localtime函数返回相同

查了一圈,原来是因为连续调用gmtimelocal函数,导致后面的调用覆盖了前面的结果。调整下打印顺序:

		t_GTM = gmtime(&timep);
		printf("sleep 2--GTMtime is %s", asctime(t_GTM));	
		t_local = localtime(&timep);
		printf("sleep 2--localtime is %s", asctime(t_local));	

再次查看输出结果:
在这里插入图片描述
可以看到,调用local之前,是正常的格林威治时间。调用local之后,被覆盖为当地时间。

需要将调用之间的值复制到 gmtime 和 localtime :
返回值指向静态分配的结构,该结构可能会被随后对任何日期和时间函数的调用所覆盖。
这是常见的行为,至少在Linux上是如此。
为什么localtime()和gmtime在c中给出相同的结果?

在链接的帖子中有人提到,可以使用memcpy,也就是连续调用之间,将返回值拷贝走。对应修改下程序:

		printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出
		
		//t_GTM = gmtime(&timep);
		t_GTM = (struct tm*)malloc(sizeof(struct tm));
		memcpy(t_GTM, gmtime(&timep), sizeof(struct tm));
		t_local = localtime(&timep);

只修改2S延时后的处理,1000000微妙的延时不做修改。再次看下输出:
在这里插入图片描述
这种方式确实有效,只是最后别忘了free掉动态分配的内存。

测试代码

#include "stdio.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h> 
#include <time.h>

int main()
{
    unsigned char i = 1;
    time_t timep;
    struct tm *t_GTM = NULL;
    struct tm *t_local = NULL;
    
    while(i--) {
		sleep(2);
		time(&timep);
        printf("sleep 2--UTC time: 0x%08x\n", timep);
		printf("sleep 2--ctime is %s", ctime(&timep));	//字符串输出
		
		//t_GTM = gmtime(&timep);
		t_GTM = (struct tm*)malloc(sizeof(struct tm));
		memcpy(t_GTM, gmtime(&timep), sizeof(struct tm));
		t_local = localtime(&timep);
		printf("sleep 2--GTMtime is %s", asctime(t_GTM));	
		printf("sleep 2--localtime is %s", asctime(t_local));	

		printf("sleep 2--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出
		printf("sleep 2--localtime current hour is %d\n", t_local->tm_hour);	
		
        usleep(1000000);
        timep = time(NULL);
        printf("usleep 1000000--UTC time: 0x%08x\n", timep);
		printf("usleep 1000000--ctime is %s", ctime(&timep));	//字符串输出
		
		t_GTM = gmtime(&timep);
		t_local = localtime(&timep);
		printf("usleep 1000000--GTMtime is %s", asctime(t_GTM));	
		printf("usleep 1000000--localtime is %s", asctime(t_local));	

		printf("usleep 1000000--GTMtime current hour is %d\n", t_GTM->tm_hour);	//整型输出	
		printf("usleep 1000000--localtime current hour is %d\n", t_local->tm_hour);

		free(t_GTM);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值