时间操作函数在实际项目开发中会经常用到,最近做项目也正好用到就正好顺便整理一下。

时间概述



由上图可知:

  1. 通过系统调用函数time()可以从内核获得一个类型为time_t的1个值,该值叫calendar时间,即从1970年1月1日的UTC时间从0时0分0妙算起到现在所经过的秒数。而该时间也用于纪念UNIX的诞生。
  2. 函数gmtime()、localtime()可以将calendar时间转变成struct tm结构体类型变量中。通过该结构体成员可以很方便的得到当前的时间信息。

    我们也可以通过函数mktime将该类型结构体的变量转变成calendar时间。
struct tm{
int tm_sec;/*秒数*/
int tm_min; /*分钟*/
int tm_hour;/*小时*/
int tm_mday;/*日期*/
int tm_mon; /*月份*/
int tm_year; /*从1990年算起至今的年数*/
int tm_wday; /*星期*/
int tm_yday; /*从今年1月1日算起至今的天数*/
int tm_isdst; /*日光节约时间的旗标*/
};
  1. asctime()和ctime()函数产生形式的26字节字符串,这与date命令的系统默认输出形式类似:

    Tue Feb 10 18:27:38 2020/n/0.
  2. strftime()将一个struct tm结构格式化为一个字符串。

常用时间函数及举例

1、time函数

头文件:time.h
函数定义:time_t time (time_t *t)
说明:
返回从1970年1月1日的UTC时间从0时0分0妙算起到现在所经过的秒数。

举例如下:

#include<stdio.h>
#include<time.h>
int main(){
time_t timep; long seconds = time(&timep);
printf("%ld\n",seconds);
printf("%ld\n",timep);
return 0;
}

输出:

有兴趣的同学可以计算下,从1970年1月1日0时0分0秒到现在经历了多少秒。

附:time_t 一路追踪发现就是从long类型经过不断的typedef ,#define定义过来的。

2、ctime函数

定义:char *ctime(const time_t *timep);
说明:将参数所指的time_t结构中的信息转换成真实世界的时间日期表示方法,然后将结果以字符串形式返回。
注意这个是本地时间。

举例如下:

#include <stdio.h>
#include<time.h>
int main(void) {
time_t timep; time(&timep);
printf("%s\n",ctime(&timep));
return 0;
}

输出:

3、gmtime函数

定义:struct tm *gmtime(const time_t *timep);
说明:将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。此函数返回的时间日期未经时区转换,而是UTC时间。

举例如下:

#include <stdio.h>
#include<time.h> int main(void) {
char *wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; time_t timep;
struct tm *p; time(&timep);
p = gmtime(&timep);
printf("%d/%d/%d ",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday);
printf("%s %d:%d:%d\n",wday[p->tm_wday],p->tm_hour,p->tm_min,p->tm_sec);
return 0;
}

输出:

4、 strftime函数

#include <time.h>
定义:
size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);
说明:
类似于snprintf函数,我们可以根据format指向的格式字符串,将struct tm结构体中信息输出到s指针指向的字符串中,最多为max个字节。当然s指针指向的地址需提前分配空间,比如字符数组或者malloc开辟的堆空间。
其中,格式化字符串各种日期和时间的详细的确切表示方法有如下多种,我们可以根据需要来格式化各种各样的含时间字符串。
%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的前两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号
返回值:
成功的话返回格式化之后s字符串的字节数,不包括null终止字符,但是返回的字符串包括null字节终止字符。否则返回0,s字符串的内容是未定义的。值得注意的是,这是libc4.4.4以后版本开始的。对于一些的老的libc库,比如4.4.1,如果给定的max较小的话,则返回max值。即返回字符串所能容纳的最大字节数。

举例如下:

  1 #include <stdio.h>
2 #include <time.h>
3
4 #define BUFLEN 255
5 int main(int argc, char **argv)
6 {
7 time_t t = time( 0 );
8 char tmpBuf[BUFLEN];
9
10 strftime(tmpBuf, BUFLEN, "%Y%m%d%H%M%S", localtime(&t)); //format date a
11 printf("%s\n",tmpBuf);
12 return 0;
13 }

执行结果如下:



输出结果表示YYYYmmDDHHMMSS

5、 asctime函数

定义:
char *asctime(const struct tm *timeptr);
说明:
将参数timeptr所指的struct tm结构中的信息转换成真实时间所使用的时间日期表示方法,结果以字符串形态返回。与ctime()函数不同之处在于传入的参数是不同的结构。
返回值:
返回的也是UTC时间。

举例如下:

#include <stdio.h>
#include <stdlib.h>
#include<time.h>
int main(void) {
time_t timep; time(&timep);
printf("%s\n",asctime(gmtime(&timep)));
return EXIT_SUCCESS;
}

输出:

6、 localhost函数

struct tm *localhost(const time_t *timep);
取得当地目前的时间和日期

举例如下:

#include <stdio.h>
#include <stdlib.h>
#include<time.h> int main(void) {
char *wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
time_t timep;
struct tm *p; time(&timep);
p = localtime(&timep);
printf("%d/%d/%d ",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday);
printf("%s %d:%d:%d\n",wday[p->tm_wday],p->tm_hour,p->tm_min,p->tm_sec);
return EXIT_SUCCESS;
}

输出:

7、mktime函数

定义:time_t mktime(struct tm *timeptr);
说明:
用来将参数timeptr所指的tm结构数据转换成从1970年1月1日的UTC时间从0时0分0妙算起到现在所经过的秒数。

举例如下:

#include <stdio.h>
#include <stdlib.h>
#include<time.h> int main(void) {
time_t timep;
struct tm *p; time(&timep);
printf("time():%ld\n",timep);
p = localtime(&timep);
timep = mktime(p);
printf("time()->localtime()->mktime():%ld\n",timep);
return EXIT_SUCCESS;
}

输出:

8、 gettimeofday函数

定义:
int gettimeofday(struct timeval *tv,struct timezone *tz);
说明:
把目前的时间由tv所指的结构返回,当地时区信息则放到有tz所指的结构中,

结构体timeval 定义如下:

struct timeval{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};

结构体timezone定义如下:

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

举例如下:

#include <stdio.h>
#include <stdlib.h>
#include<time.h>
#include<sys/time.h> int main(void) {
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
printf("tv_sec :%d\n",tv.tv_sec);
printf("tv_usec: %d\n",tv.tv_usec);
printf("tz_minuteswest:%d\n",tz.tz_minuteswest);
printf("tz_dsttime:%d\n",tz.tz_dsttime);
return EXIT_SUCCESS;
}

输出:

综合实验

现在我们利用这些时间函数,来实现一个定时执行某个任务得功能。

功能

  1. 程序运行时要记录当前日志文件的最后修改时间;
  2. 每个10秒钟就检查下log文件是否被修改,如果没有被修改就休眠10秒钟;
  3. 如果log文件被修改了,就将当前的日志文件拷贝成备份文件,备份文件名字加上当前时间;
  4. 通过curl发送给ftp服务器;
  5. 删除备份文件,重复步骤2。

程序流程图如下:

函数功能介绍

init()

首先记录当前log文件时间,并记录到全局变量last_mtime中。

check_file_change()

读取文件最后修改时间,并和last_mtime进行比较,如果相同就返回0,不同就返回1.

file_name_add_time()

将当前的日志文件拷贝成备份文件,备份文件名字加上当前时间。

stat()​

得到对应文件的属性信息,存放到struct stat结构体变量中。

运行截图:

第一步:



因为log文件没有被修改过,所以程序不会上传。

第二步:

手动输入字符串 yikoulinux 到日志文件 t.log中。

第三步:

因为文件发生了改变,所以打印“file updated”,同时可以看到curl上传文件的log信息。

以下是FTP服务器的根目录,可以看到,上传的日志文件:t-2020-7-26-1-19-45.log

【补充】

  1. 配置信息,直接在代码中写死,通常应该从配置文件中读取,为方便读者阅读,本代码没有增加该功能;
  2. FTP服务器搭建,本文没有说明,相关文件比较多,大家可以自行搜索,一口君用的是File zilla;

  3. 通常这种需要长时间运行的程序,需要设置成守护进程,本文没有添加相应功能,读者可以自行搜索。如果强烈要求可以单开一篇详细介绍。
  4. 代码中time的管理函数,请读者自行搜索相关文章。
  5. curl也提供了相关的函数库curl.lib,如果要实现更灵活的功能可以使用对应的api。
  6. 之所以先把文件拷贝成备份文件,主要是考虑其他模块随时可能修改日志文件,起到一定保护作用。

代码如下

代码如下:

/***************************************************
Copyright (C) 公众号: 一口linux
***************************************************/
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h> typedef struct stat ST;
unsigned long last_mtime; /*用户名密码暂时写死,实际应该保存在配置文件*/
char name[32]="user";
char pass[32] ="123456";
char ip[32] ="192.168.43.117";
char filename[32]="t.log";
char dstfile[256] ={0}; int init(void)
{
//准备结构体
ST status; //调用stat函数
int res = stat(filename,&status);
if(-1 == res)
{
perror("error:open file fail\n");
return 0;
}
last_mtime = status.st_mtime;
printf("init time:%s \n",ctime(&last_mtime));
return 1;
} int check_file_change(void)
{
//准备结构体
ST status; //调用stat函数
int res = stat(filename,&status);
if(-1 == res)
{
perror("error:open file fail\n");
return 0;
}
// printf("old:%s new:%s",ctime(&last_mtime),ctime(&status.st_mtime));
if(last_mtime == status.st_mtime)
{
printf("file not change\n");
return 0;
}else{
printf("file updated\n");
last_mtime = status.st_mtime;
return 1;
} }
void file_name_add_time(void)
{
ST status;
time_t t;
struct tm *tblock;
char cmd[1024]={0}; t = time(NULL);
tblock = localtime(&t); sprintf(dstfile,"t-%d-%d-%d-%d-%d-%d.log",
tblock->tm_year+1900,
tblock->tm_mon,
tblock->tm_mday,
tblock->tm_hour,
tblock->tm_min,
tblock->tm_sec);
sprintf(cmd,"cp %s %s",filename,dstfile);
// printf("cdm=%s\n",cmd);
system(cmd);
}
int main(void)
{ char cmd[1024]={0}; init();
while(1)
{
if(check_file_change() == 1)
{
file_name_add_time();
sprintf(cmd,"curl -u %s:%s ftp://%s/ -T %s",name,pass,ip,dstfile);
// printf("cdm=%s\n",cmd);
system(cmd);
unlink(dstfile);
}
sleep(10);
}
}

请关注公众号「一口Linux」

C语言操作时间函数time.ctime,实现定时执行某个任务小例子的更多相关文章

  1. C 语言 clock() 函数,例:计算多项式值

    C 语言 clock() 函数,例:计算多项式值 /** * clock(): 捕捉从程序开始运行到 clock() 被调用时所耗费的时间. * 这个时间单位是 clock tick, 即" ...

  2. C 语言 时间函数使用技巧(汇总)

    time.h 头文件 是 C 语言中 有关 时间的函数所储存的头文件 #include <time.h> 在介绍时间函数用法之前,我们首先要了解在 time.h 头文件中已经声明了的一个结 ...

  3. C语言pow函数编写

    C语言pow函数编写 #include<stdio.h> double chaoba(double f,double q); //声明自定义函数 void main(void) { dou ...

  4. C语言-自定义函数

    C语言自定义函数 --1-- 自定义函数定义 1.1 无参无返回值函数 1.2 无参有返回值函数 1.3 有参无返回值函数 1.4 有参有返回值函数 --2-- 函数的参数 2.1 形式参数介绍和使用 ...

  5. C语言scanf函数详细解释

    原文链接 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准 ...

  6. C语言printf()函数:格式化输出函数

    C语言printf()函数:格式化输出函数 头文件:#include <stdio.h> printf()函数是最常用的格式化输出函数,其原型为:     int printf( char ...

  7. C语言的函数

    "函数"在英文的翻译是"function",无论在自然科学还是计算机科学都是这个词,而"function"的本意是"功能" ...

  8. c语言main函数返回值、参数详解(返回值是必须的,0表示正常退出)

    C语言Main函数返回值 main函数的返回值,用于说明程序的退出状态.如果返回0,则代表程序正常退出:返回其它数字的含义则由系统决定.通常,返回非零代表程序异常退出. 很多人甚至市面上的一些书籍,都 ...

  9. Go语言示例-函数返回多个值

    Go语言中函数可以返回多个值,这和其它编程语言有很大的不同.对于有其它语言编程经验的人来说,最大的障碍不是学习这个特性,而是很难想到去使用这个特性. 简单如交换两个数值的例子: package mai ...

  10. 【学习笔记】【C语言】函数

    一. 什么是函数 任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”.所以,你可以说C语言程序是由函数构成的. 比如你用C语言编写了一 ...

随机推荐

  1. Linux设备模型:1、设计思想

    背景 搞Linux搞这么久,一直在调试各种各样的驱动.却发现对Linux驱动有太多不够了解的地方.因此转载了 蜗窝科技 的有关文章,作为学习. 内容有少量纠正,样式有做调整. 作者:wowo 发布于: ...

  2. VulnHub_DC-1渗透流程

    DC-1 DC-1 是一个专门建造的易受攻击的实验室,目的是在渗透测试领域获得经验. 它旨在为初学者提供挑战,但它的难易程度取决于您的技能和知识,以及您的学习能力. 要成功完成此挑战,您将需要 Lin ...

  3. C++ Constructor And Destructor

    if you have problems with constructors and destructors, you can insert such print statements in cons ...

  4. redis出现错误提示MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for......

    某天,redis出现了这样一个错误提示: MISCONF Redis is configured to save RDB snapshots, but is currently not able to ...

  5. 从DDPM到DDIM

    从DDPM到DDIM (一) 现在网络上关于DDPM和DDIM的讲解有很多,但无论什么样的讲解,都不如自己推到一边来的痛快.笔者希望就这篇文章,从头到尾对扩散模型做一次完整的推导. DDPM是一个双向 ...

  6. MViT:性能杠杠的多尺度ViT | ICCV 2021

    论文提出了多尺度视觉Transformer模型MViT,将多尺度层级特征的基本概念与Transformer模型联系起来,在逐层扩展特征复杂度同时降低特征的分辨率.在视频识别和图像分类的任务中,MViT ...

  7. oeasy教您玩转vim - 49 - # 命令进阶

    ​ 命令进阶 回忆上节课内容 我们上次研究vim的历史 为什么会有行编辑器这种东西 竟然是当年 没有显示器只有纸的时代的无奈之举 vim进化到今天 依然还有好多人使用 而且ssh连接的时候直接vim就 ...

  8. [oeasy]python0018_ ASCII_字符分布_数字_大小写字母_符号_黑暗森林

    ​ 打包和解包 回忆上次内容 decode 就是解码 解码和编码可以转化 encode 编码 decode 解码 互为逆过程 大小写字母之间序号全都相差(​​32​​)​​10进制​​ ​ 编辑 这是 ...

  9. ASP.NET Core 程序集注入(二)

    public void ConfigureServices(IServiceCollection services) { string strValue = Configuration.GetSect ...

  10. Java代码实现七夕魔方照片墙

    创建一个七夕魔方照片墙是一个相对复杂的任务,涉及到前端展示和后端数据处理.在这里,我会提供一个简化的Java后端示例,用于生成一个模拟的"照片墙"数据模型,并给出一个基本的前端HT ...