Linux中的时间编程
文章目录
前言
在Linux的应用编程或者内核编程中,我们经常会用到一些简单的软件延时,今天就来学习一些这些延时的使用方法。前面两部分是延时函数,后面是Linux时间编程。
一、sleep系统函数
sleep函数是在系统编程时使用的函数,或者说是在进行Linux应用编程才使用的。简单介绍如下:
1.1 sleep秒延时
函数原型:
unsigned int sleep(unsigned int seconds);
返回值说明:返回无符号的整形数值,如果延时成功则返回 0,如果延时过程中被打断,则返回剩余的秒数。
例如 sleep(5),返回值为 3,那么实际延时就是 5-3=2 秒。
1.2 usleep微秒延时
u前缀即说明这个是us级的延时函数,函数原型:
int usleep(useconds_t usec);
参数:usec
需要<1000000
返回值:延时成功返回0,失败直接返回-1
例如:usleep(10),表示延时 10 微秒
简单示例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
while(1)
{
printf("LED ON!\n");
if(sleep(1))
printf("sleep(1) failed!\n");
if(usleep(1000))
printf("usleep(1000) failed!\n");
printf("LED OFF!\n");
if(sleep(1))
printf("sleep(1) failed!\n");
if(usleep(1000))
printf("usleep(1000) failed!\n");
}
exit(0);
}
编译测试,执行后大约2s打印输出一次LED状态。
二、delay内核函数
delay系列函数是在内核中使用的,当我们进行驱动编写或者硬件初始化时序时会用到一些。下面是delay
函数的简单介绍。
2.1 mdelay毫秒延时
m前缀即表示毫秒延时,函数原型:
void mdelay(unsigned long msecs);
使用示例:mdelay(10),表示延时 10 毫秒。
2.2 udelay微秒延时
u前缀即表示微秒延时,函数原型:
void udelay(unsigned long usecs);
使用示例:udelay(10),表示延时 10 us。
2.2 ndelay纳秒延时
n前缀即表示纳秒延时,函数原型:
void ndelay(unsigned long nsecs);
使用示例:ndelay(10),表示延时 10 ns。
说明
Linuxux下的延时函数主要有sleep
、usleep
、ndelay
、udelay
、mdelay
等,
Linux 系统编程下用到的延时函数在头文件“#include <unistd.h>”
中,包括函数 sleep
、usleep
。
Linux 内核中用到的延时函数在“#include <linux/delay.h>”
中,包括函数 ndelay
、udelay
、mdelay
。
特别注意要分开内核编程和系统编程中使用的延时函数,这两类函数是不能混用的。
三、Linux时间
在Linux中有几个时间需要进行区分,UTC时间、UNIX纪元时间、格林尼治标准时间(GMT)。
UTC时间即世界统一时间;
Unix 纪元时间是指从 1970 年 1 月 1 日 00:00:00 UTC 开始所经过的秒数,也叫机器日历时间;
GMT 是指太阳经过英国格林尼治的时间。在英国很 NX 的时候,以格林尼治为 0 度经线,
将世界分为 24 个时区。
在Linux中时间日期使用Unix纪元时间的方式,有效位是秒。
3.1 时间函数
3.1.1 time函数
time
函数在头文件“#include <time.h>”
声明 ,通过time
函数可以获取UTC时间,单位为秒s。
函数原型:
time_t time(time_t *t);
time_t
是long类型的整数,参数t
可以省略设置为NULL,
此时会返回当前的日历时间(秒单位);当传递参数给t
时,获取到的日历时间会传递给该参数,此时返回值-1代表失败,返回0。简单代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
int main(int argc, char **argv)
{
time_t Ntime;
if(time(&Ntime) > 0)
printf("time: 0x%lx\n", Ntime);
sleep(1);//延时1s
Ntime = time(NULL);
printf("time: 0x%lx\n", Ntime);
exit(0);
}
结果:
注意:当time传入空参数时,NULL
必不可少,否则会报错。
3.1.2 gettimeofday/settingofday函数
time()
函数获取的是s级的时间,要获取更高精度的时间,可以通过两个高精度的时间函数,gettimeofday/settingofday函数,这两个函数需要包含的头文件为`#include <sys/time.h>` 。
函数原型分别为:
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
结构体timeval
:
struct timeval {
time_t tv_sec;/* seconds */
suseconds_t tv_usec;/* microseconds */
};
结构体timezone
:
struct timezone {
int tz_minuteswest;/* minutes west of Greenwich,格林威治时间的时差 */
int tz_dsttime;/* type of DST correction,时间修正的方式 */
};
gettimeofday()
用于获取当前的时间,可以获取到秒、微秒级时间,settimeofday()
则用于设置当前系统的时间,可以设置的也是秒、微秒级的时间,timezone
是时区,可以传入NULL
。
代码示例:
#include <stdio.h>
#include <sys/time.h>
void loop(void)
{
int i,j;
for(i=0;i<10;i++)
for(j=0;j<10;j++);
}
int main(int argc, char **argv)
{
struct timeval tim1;
struct timeval tim2;
struct timeval Stim;
gettimeofday(&tim1, NULL);
printf("tim1->tv_usec: %ld\n", tim1.tv_usec);
loop();
gettimeofday(&tim2, NULL);
printf("tim2->tv_usec: %ld\n", tim2.tv_usec);
printf("tim2-tim1= %ldus\n",tim2.tv_usec-tim1.tv_usec);
Stim.tv_sec = 0;
Stim.tv_usec = 100;
settimeofday(&Stim, NULL);
printf("after set time,the time is:%lds %lds\n", Stim.tv_sec, Stim.tv_usec);
return 0;
}
输出结果:
3.2 时间转换
上面获取到的时间的格式是16进制的,为了直观一点,可以使用时间转换函数,对时间数据进行格式转换。下面介绍方法。
3.2.1 时间结构体
常用时间结构体tm
:
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]。 - 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.2.2 转换函数
-
ctime函数
ctime
函数可以把时间转换为字符串格式,返回值即为转换后的字符串指针。函数原型:
char *ctime(const time_t *timep);
-
gmtime函数
gmtime
函数将时间转换为GMT格林尼治时间,保存为上面我们说到的tm
类型中。函数原型:
struct tm *gmtime(const time_t *timep);
-
asctime函数
asctime
函数也是转换为字符串,但是传入的参数是tm
结构体。函数原型:
char *asctime(const struct tm *tm);
-
localtime函数
localtime
函数将时间转换为本地时间,函数原型:struct tm *localtime(const time_t *clock);
代码示例:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char **argv) { time_t Ntime,Ltime; struct tm *tmStruct = NULL,*localtm = NULL; if(time(&Ntime) >= 0) printf("time():0x%lx\n", Ntime); printf("--------------------------------\n"); printf("ctime(): %s\n", ctime(&Ntime)); printf("--------------------------------\n"); if((tmStruct = gmtime(&Ntime)) != NULL) { printf("gmtime sec: %d\n", tmStruct->tm_sec); printf("gmtime min: %d\n", tmStruct->tm_min); printf("gmtime hour: %d\n", tmStruct->tm_hour); printf("gmtime mday: %d\n", tmStruct->tm_mday); printf("gmtime mon: %d\n", tmStruct->tm_mon+1); printf("gmtime year: %d\n", tmStruct->tm_year+1900); printf("gmtime wday: %d\n", tmStruct->tm_wday); printf("gmtime yday: %d\n", tmStruct->tm_yday); printf("gmtime isdst: %d\n", tmStruct->tm_isdst); } printf("--------------------------------\n"); printf("asctime(gmtime): %s\n", asctime(tmStruct)); printf("--------------------------------\n"); time(&Ltime); if((localtm = localtime(&Ltime)) != NULL) { printf("gmtime sec: %d\n", localtm->tm_sec); printf("gmtime min: %d\n", localtm->tm_min); printf("gmtime hour: %d\n", localtm->tm_hour); printf("gmtime mday: %d\n", localtm->tm_mday); printf("gmtime mon: %d\n", localtm->tm_mon+1); printf("gmtime year: %d\n", localtm->tm_year+1900); printf("gmtime wday: %d\n", localtm->tm_wday); printf("gmtime yday: %d\n", localtm->tm_yday); printf("gmtime isdst: %d\n", localtm->tm_isdst); } printf("localtime():%s", asctime(localtm)); exit(0); }
执行结果:
注意:转换函数的参数需要经过time()
进行获取,然后才可以进行转换,否则容易出现错误导致时间不对。