手里的智能锁项目 , 做了个菜单,设置时间的功能 , 弄了大半天弄完了, 记录一下方法
1设置时间
设置时间需要2个结构体,分别是struct tm 和struct timeval还有一个长整型的time_t类型, 总共4个步骤。
1.1 把tm类型里的成员(年 月 日 时 分 秒)逐个赋值
struct tm { /* * the number of seconds after the minute, normally in the range * 0 to 59, but can be up to 60 to allow for leap seconds */ int tm_sec; /* the number of minutes after the hour, in the range 0 to 59*/ int tm_min; /* the number of hours past midnight, in the range 0 to 23 */ int tm_hour; /* the day of the month, in the range 1 to 31 */ int tm_mday; /* the number of months since January, in the range 0 to 11 */ int tm_mon; /* the number of years since 1900 */ long tm_year; /* the number of days since Sunday, in the range 0 to 6 */ int tm_wday; /* the number of days since January 1, in the range 0 to 365 */ int tm_yday; };
1.2 通过mktime函数 , 计算出从1970年到现在经过的总共秒数,time_t类型的变量来接收返回值,伪代码如下
time_t timep = mktime(&tm);//当前的tm结构体里的年月日时分秒都已经赋值过
1.3 把mktime计算出来的秒填到tv结构体里的tv_sec域,伪代码如下
struct timeval { time_t tv_sec; /* seconds */ long tv_usec; /* microseconds */ };
tv.tv_sec = timep;
tv.tv_usec = 0;
1.4 调用系统函数settimeofday(&tv, NULL),设置就OK了 ,
settimeofday函数的原型是 int settimeofday(const struct timeval *tv, struct timezone *tz); 参数tv表示时间的结构体,参数tz表示当地时区(如DST_USA,DST_AUST等等),如果对tz或者tv其中一项不感兴趣, 直接像我一样填NULL就行了。
需要注意的是 , settimeofday这个函数只能由root用户调用 , 如果其他用户调用的话会报错EPERM, 即权限不够。
2 代码:
#include <stdio.h> #include <time.h> //struct tm #include <sys/time.h>// struct timeval int main(void) { // Set time 需要的struct tm和struct timeval两个结构体以及一个time_t类型 struct tm set_tm; struct timeval set_tv; time_t timep; //1 填充struct tm结构体的实例 set_tm.tm_year = 2018 - 1900; set_tm.tm_mon = 6 - 1; set_tm.tm_mday = 10; set_tm.tm_hour = 15; set_tm.tm_min = 55; set_tm.tm_sec = 5; //2 通过mktime函数把struct tm结构体里的值转换成秒 timep = mktime(&set_tm); //3 把1970年到现在总共经过的秒数填充到struct timeval的tv_sec项 set_tv.tv_sec = timep; set_tv.tv_usec = 0; //4 调用settimeofday函数, 设置系统时间 if (settimeofday(&set_tv, (struct timezone *)0) < 0) { printf("set time error !\n"); return -1; } return 0; }
运行结果:
第一次./a.out 显示set time error的原因 , 就是因为我不是root用户 , 第二次运行之前加上sudo就设置成功了。
(t是我自己写的一个命令,平时用来显示当前系统时间的)
2 获取系统时间
因为获取系统时间其实也就是设置系统时间的逆向操作, 原理是一样的, gettimeofday函数获取到1970年到现在总共的秒数,然后用localtime函数通过总共秒数来计算出其他成员的值, 逐个填充到struct tm结构体的成员中,所以我就直接上代码了
3 获取系统时间代码:
#include <stdio.h> #include <time.h> #include <sys/time.h> int main(void) { struct tm *get_tm; struct timeval get_tv; gettimeofday(&get_tv, NULL); get_tm = localtime(&get_tv.tv_sec); #if 0 printf("%s \n", asctime(get_tm)); #else printf("year %d mon %d mday %d hour %d min %d sec %d \n", get_tm->tm_year + 1900, get_tm->tm_mon + 1, get_tm->tm_mday, get_tm->tm_hour, get_tm->tm_min , get_tm->tm_sec); #endif return 0; }
运行结果如下
上面显示的方式是调用系统的asctime函数把struct tm转换成字符串来显示, 下面是每个成员逐个手动去打印。
最后提醒一下各位小伙伴 , 如果设置了错误的系统时间,可以使用ntp来同步系统时间,我使用的是阿里云的时间服务器,
命令如下 sudo ntpdate ntp.aliyun.com