在嵌入式编程中中。常常须要输出系统的当前时间、计算程序的运行时间、使用计时器等。近期也做了不少关于时间的操作。今天就认真总结一下,部分内容是在网上看到的。自己经过验证总结出来。

1、时间的类型

1.格林威治标准时间

   coordinated universal time(UTC)是世界标准时间,即常说的格林威治标准时间(greenwich mean time,GMT)。

2.日历时间

   日历时间(calendar time)是用"一个标准时间点(如1970年1月1日0点)到此时经过的秒数"来表示的时间。

2、经常使用时间函数的API

1、获取日历时间

   #include <time.h>

   time_t time(time_t *tloc)

   函数功能 : 获取日历时间,即从1970年1月1日0点到如今所经历的秒数.

   參数 : 通常设置为NULL

 (time_t在time.h中定义:typedef long int time_t)time_t记录自1970年1月1日凌晨以来的秒数,在Linux/Unix上定义为long int类型,在32位系统上,time_t最多仅仅能记录2,147,483,647秒,也就是说到了2038年将会产生溢出(这就是为什么非常多嵌入式设备日期仅仅可以设置到2038年的原因),但在64位系统上不会出现此问题。函数double
difftime(time_t time1, time_t time0);用于比較两个time_t类型的值。

#include <time.h>
void main()
{
long lSeconds = 0;
lSeconds = time(NULL);
printf("seconds = %ld\n", lSeconds);
}

2、将日历时间转换为格林威治标准时间和本地时间

通经常使用户得到日历时间的秒数后能够将这些秒数转化为更easy接受的时间表示方式,这些表示时间的方式有格林威治时间、本地时间等首先介绍一个表示时间经常使用的数据结构。

 struct tm

 {

      int tm_sec;   //秒值

      int tm_min;   //分钟值

      int tm_hour;  //小时值

      int tm_mday;  //本月第几日

      int tm_mon;   //本年第几月

      int tm_year;  //tm_year+1900=哪一年

      int tm_wday;  //本周第几日

      int tm_yday;  //本年第几日

      int tm_isdst; //日光节约时间

 }
-----------------------------------------------------------------
 tm_sec         |       秒,范围是0~59。                        
 tm_min         |       分,范围是0~59。                        
 tm_hour        |       时,范围是0~23。                        
 tm_mday        |       日,范围是1~31。                        
 tm_mon         |       月,范围是0~11。注意是0到11。           
 tm_year        |       年,自1900以来的年数。                  
 tm_wday        |       星期几。从星期天開始计算,范围是0~6。
 tm_yday        |       一年中的哪一天,0~365。                 
 tm_isdst       |       夏令时间(DST)的一个标志。             
-----------------------------------------------------------------
函数介绍:

struct tm *gmtime(const time_t *timep)

 函数功能  : 将日历时间转化为格林威治标准时间。并保存在tm结构

參数:日历时间的返回值

struct tm* localtime(const time_t *timep)

 函数功能:将日历时间转化为本地时间,并保存至tm结构

 參数:日历时间的返回值。

例:

#include <stdio.h>
#include <time.h>
int main(void)
{
   struct tm *local;
time_t t;
t = time(null); //获取日历时间
local = localtime(&t);//将日历时间转化为本地时间,并保存在struct tm结构中
printf("local hour is :%d\n",local->tm_hour);
local = gmtime(&t); //将日历时间转化为格林威治时间。并保存在struct tm结构中
printf("utc hour is :%d\n",local->tm_hour);
return 0;
}

3、时间显示

利用函数gmtime()、localtime()能够将日历时间转化为格林威治时间和本地时间,尽管用户可通过结构体tm来获取这些时间值,但看起来还不方便,最好是将全部的信息。如年、月、日、星期、时、分、秒以字符串的形式显示出来。

char *asctime(const struct tm *tm)

函数功能:将tm格式的时间转化为字符串

參数:日历时间的返回值

比如: SAT Jul 30 08:43:03 2005

该函数必须依照以下3个步骤来进行.

   <1>使用函数time()来获取日历时间

   <2>使用函数gmtime()将日历时间转化为格林威治标准时间

   <3>使用函数asctime()将tm格式的时间转化为字符串

例:

#include <time.h>
#include <stdio.h> int main(void)
{
struct tm *ptr;
time_t lt;
lt = time(null); //获取日历时间
ptr = gmtime(<); //转化为格林威治时间*/
printf(asctime(ptr)); //以格林威治时间的字符串方式打印
printf(ctime(<)); //以本地时间的字符串方式打印*/
return 0;
}

char *ctime(const time_t *timep)

 函数功能:将日历时间转化为本地时间的字符串形式

 參数:日历时间的返回值。

该函数.必须依照以下2个步骤来进行.

   <1>使用函数time()来获取日历时间

   <2>使用函数ctime()将日历时间直接转化为字符串

PS:有time函数将time_t值转换为struct tm类型值,函数mktime 能够将struct
tm类型值转换为time_t类型的值
。其原型为:

time_t mktime(struct tm *tm);

4、计算事件耗时

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

函数功能 : 获取从今日凌晨(0:0:0)到如今的时间差。经常使用于计算事件耗时

參数1 : 存放从今日凌晨(0:0:0)到如今的时间差,时间差以秒或微秒为单位,以结构体形式存放


參数2 : 常设置为null

函数使用方法:能够在做某件事情之前调用gettimeofday()。在做完该件事情之后调用gettimeofday(),两个函数的參数1的差就是做该事情所消耗的时间。

也常常在程序中作为定时器处理,比方每隔多长时间时间运行一次什么事件。

struct timeval

{

           int tv_sec;    //秒数

           int tv_usec;   //微秒数

}

// 计算时间差。单位毫秒
int elapsed_time(struct timeval *ct, struct timeval *lt)
{
int elapsed = (ct->tv_sec - lt->tv_sec) * 1000 + (ct->tv_usec - lt->tv_usec) / 1000;
return elapsed;
}

5、设置系统时钟

这里要介绍两个函数,同time和gettimeofday相应,stime和settimeofday,原型例如以下:

int stime(time_t *t);
int settimeofday(const struct timeval *tv, const struct timezone *tz);

仅仅是settimeofday设置的时间比stime更精确罢了。

6、延时函数

(1)unsigned int sleep(unsigned int seconds)

函数功能 : 使程序睡眠seconds秒

參数 : 须要休眠的秒数

(2)void usleep(unsigned long usec)

函数功能 : 使程序睡眠usec微秒

參数 : 须要休眠的秒数

7、定时器

unsigned alarm(unsigned seconds);

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void alarm_handler(int signum)
{
rintf("Five seconds passed!\n");
}
void func(void)
{
signal(SIGALRM, alarm_handler);
alarm(5);
pause();
}
int main(void)
{
func();
return 0;
}

程序将在5秒之后运行alarm_handler函数,这里还使用了pause函数。用于挂起进程直到捕捉到一个信号时才退出。注意alarm一次仅仅能发送发送一个信号。假设要再次发送信号。须要又一次调用alarm函数。

除了alarm外。还能够使用setitimer来设置定时器,使用getitimer来获取定时器的状态,原型例如以下:

int setitimer(int which, const struct itimerval *restrict value, struct itimerval *restrict ovalue);

int getitimer(int which, struct itimerval *value);

说明:


须要包括头文件sys/time.h

which參数有三种取值:

ITIMER_REAL 按实际时间记时,时间到了之后发送SIGALRM信号。相当于alarm。

ITIMER_VIRTUAL 仅当进程运行时才进行记时,发送SIGVTALRM信号。

ITIMER_PROF 当进程运行时和系统运行该进程时都记时。发送的是SIGPROF信号。

struct itimerval用来指定定时时间。定义例如以下:

struct itimerval 

{

struct timerval it_interval;
/* next value */

struct timerval it_value;
/* current value */

};

在setitimer函数中,ovalue假设不为空,则保留上次调用设置的值。

3、时间函数的安全使用方法

      在写代码的时候。常常会用到读取系统时间的函数。

localtime函数不是线程安全的。假设在多线程里调用localtime函数,非常可能会出现故障。

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

相同gmtime函数和gmtime_r函数



char *asctime(const struct tm *tm);

char *asctime_r(const struct tm *tm, char *buf);


char *ctime(const time_t *timep);

char *ctime_r(const time_t *timep, char *buf);



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);



time_t mktime(struct tm *tm);

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

localtime() 函数将日历时间timep转换为用户指定的时区的时间。

这个函数的行为好像是它调用了tzset(3) 而且将外部变量tzname设置为当前时区的信息。将timezone设为UTC和本地标准时间的差值,而且,假设在一年的部分时间使用日光节约规则时将daylight设置为非空值。返回值指向一个静态分配的结构,该结构可能会被接下来的不论什么日期和时间函数调用覆盖。

localtime_r()函数功能与此同样,可是它能够将数据存储到用户提供的结构体中。它不须要设置tzname。

4、时间函数功能測试

例1:

#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;
}

输出结果:

xzg@byxc-PDSML:~/test$ gcc -o time time.c 

xzg@byxc-PDSML:~/test$ ./time 

UTC = Tue Jul 15 01:41:08 2014

LOC = Tue Jul 15 09:41:08 2014

LOC = Tue Jul 15 09:41:08 2014

系统时间使用了UTC,能够看到“本地时间=
UTC时间 + 8”,输出正确。

例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 = gmtime( &cur_time );
if( NULL == utc_tm )
{
perror("gmtime" );
return -1;
} <strong>printf("UTC = %s", asctime(utc_tm) );</strong> 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;
}

输出结果:

xzg@byxc-PDSML:~/test$ gcc -o time1 time1.c 

xzg@byxc-PDSML:~/test$ ./time1

UTC = Tue Jul 15 02:00:38 2014

LOC = Tue Jul 15 10:00:38 2014

LOC = Tue Jul 15 10:00:38 2014

xzg@byxc-PDSML:~/test$

例3:

#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;
}
<strong>printf("UTC = %s", asctime(utc_tm) );</strong>
printf("LOC = %s", asctime(local_tm) );
printf("LOC = %s", ctime(&cur_time) );
return 0;
}

输出结果:

xzg@byxc-PDSML:~/test$ gcc -o time1 time1.c 

xzg@byxc-PDSML:~/test$ ./time1              

UTC = Tue Jul 15 10:03:26 2014

LOC = Tue Jul 15 10:03:26 2014

LOC = Tue Jul 15 10:03:26 2014

这程序输出有错,UTC时间和本地时间同样了“可能会被接下来的不论什么日期和时间函数调用覆盖”造成的。

总结:

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

Linux 下的时间编程总结的更多相关文章

  1. Linux下的C编程实战

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...

  2. Linux 应用层的时间编程【转】

    转自:https://blog.csdn.net/chinalj2009/article/details/21223681 浅析 Linux 中的时间编程和实现原理,第 1 部分: Linux 应用层 ...

  3. 浅析 Linux 中的时间编程和实现原理一—— Linux 应用层的时间编程【转】

    本文转载自:http://www.cnblogs.com/qingchen1984/p/7007631.html 本篇文章主要介绍了"浅析 Linux 中的时间编程和实现原理一—— Linu ...

  4. Linux下长时间ping网络加时间戳并记录到文本

    Linux下长时间ping网络加时间戳并记录到文本   由于一些原因,比如需要检查网络之间是否存在掉包等问题,会长时间去ping一个地址,由于会输出大量的信息而且最好要有时间戳,因此我们可以使用简单的 ...

  5. Linux下TCP网络编程与基于Windows下C#socket编程间通信

    一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...

  6. Linux下C语言编程实现spwd函数

    Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...

  7. linux下的c编程

    linux下的c编程 Linux 系统上可用的 C 编译器是 GNU C 编译器, 它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布.GNU  C 对标准 C 进行一系列扩展,以增强标准 ...

  8. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

  9. LINUX下C语言编程基础

    实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用 ...

随机推荐

  1. 长脖子鹿省选模拟赛 [LnOI2019SP]快速多项式变换(FPT)

    本片题解设计两种解法 果然是签到题... 因为返回值问题T了好久... 第一眼:搜索大水题? 然后...竟然A了 #include<cstdio> #include<queue> ...

  2. ROS-导航功能-Gazebo

    前言:仿真的整体思路,先启动仿真环境,再启动导航功能. 前提:已下载并编译了相关功能包集,如还未下载,可通过git下载:https://github.com/huchunxu/ros_explorin ...

  3. 通过学习Date和Calendar时写的日历

    package com.etc.util; import java.util.Calendar; import java.util.Scanner; public class Calendar2 { ...

  4. CSS的常用属性(二)

    盒子模型之边框 border-(top/bottom/left/right)-style: solid 边框的风格 如(solid 实线,dotted 点线,dashed 虚线) border-top ...

  5. 《java数据结构与算法》系列之“开篇”

    大学的时候学习数据结构,当时吧虽然没挂这门课,但是确实学的不咋地,再但是其实自己一直都觉得数据结构很重要,是基础,只有基础好了,后面的路才能走的更好. 懒惰真的是天下的罪恶之源.所以一直到现在都毕业了 ...

  6. Linux 与 Windows 文件互传(VMWare)

    虚拟机无桌面的Linux 与 物理机Windows 文件互传有很多种方法,现在先说一种通过共享文件夹的形式,其他方法后续再补充 1.     背景 1)        虚拟机系统:VMWare无桌面的 ...

  7. 开源作品-PHP写的Redis管理工具(单文件绿色版)-SuRedisAdmin_PHP_1_0

    前言:项目开发用到了Redis,但是在调试Redis数据的时候,没有一款通用的可视化管理工具.在网络找了一些,但是感觉功能上都不尽人意,于是决定抽出一点时间,开发一个用起来顺手的Redis管理工具.秉 ...

  8. Window8.1下安装Matplotlib库

    有两种方法: 直接选用一些预打包库软件,如WinPython, Python(x,y), Enthought Canopy, or Continuum Anaconda.这些软件中已包含有Matplo ...

  9. CorelDRAW2019版本下载,CorelDRAW最新版新增功能(全)

    使用CorelDRAW 2019,随时随地进行设计创作.无论您使用的是 Windows 或 Mac,都能在为您的平台量身设计的直观界面中,随心所欲地自由创作.无论您是热衷于像素,执迷于无缝输出或沉浸于 ...

  10. 玲珑杯#20 C 漆黑的太阳——莫队

    题目:https://www.ifrog.cc/acm/problem/1155 题解:https://www.ifrog.cc/acm/solution/28 1.如何不重复计算一个值 自己想的是对 ...