linux时钟操作接口

linux获取时钟接口

概述

linux系统开发环境中,需要获取各种类型时钟,针对这些情况做了一个简单整理。
首先对时钟接口的需求大概包括有:
1:获取当前时钟,这个在内核中一般表现为UTC时钟(从1970.1.1 00:00:00到当前时间的秒及纳秒)
2:获取系统启动后单调时钟,即系统启动以来的秒和纳秒数
3:设置时钟
4:针对时钟不同结构体数据之间的转换

时区

时区分类:
UTC:
整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal Time Coordinated)

GMT:
格林威治标准时间 (Greenwich Mean Time)指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。(UTC与GMT时间基本相同,本文中不做区分)

CST:
中国标准时间 (China Standard Time)

DST:
夏令时(Daylight Saving Time) 指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用。(中国不使用)

GMT + 8 = UTC + 8 = CST

linux系统时钟一般操作

读写时钟

//查看时钟
kongcb@tcu-Lenovo:~$ date
2022年 05月 17日 星期二 14:17:25 CST
kongcb@tcu-Lenovo:~$ date -R
Tue, 17 May 2022 14:17:30 +0800		//+0800表示东八区时区

//设置时钟
kongcb@tcu-Lenovo:~$ sudo date -s "20220517 14:25"
[sudo] password for kongcb: 
2022年 05月 17日 星期二 14:25:00 CST
kongcb@tcu-Lenovo:~$ date -R
Tue, 17 May 2022 14:25:08 +0800

时区操作

//获取时区
kongcb@tcu-Lenovo:~$ timedatectl
Local time:2022-05-17 14:26:17 CST
Universal time:2022-05-17 06:26:17 UTC	//看到UTC时间比CST晚8小时
Timezone: Asia/Chongqing (CST, +0800)	//时区CST,亚洲重庆
NTP enabled: yes
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
    
//设置时区
kongcb@tcu-Lenovo:~$ sudo timedatectl set-timezone Asia/Shanghai
kongcb@tcu-Lenovo:~$ timedatectl
Local time:2022-05-17 14:31:43 CST
Universal time:2022-05-17 06:31:43 UTC
Timezone: Asia/Shanghai (CST, +0800)
NTP enabled: yes
NTP synchronized: no
RTC in local TZ: no
DST active: n/a    
    
//查看时区
kongcb@tcu-Lenovo:~$ timedatectl list-timezones
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
........    

同步网络时钟

//同步网络时钟
kongcb@tcu-Lenovo:~$ sudo apt-get install ntp
Reading package lists... Done
Building dependency tree       
........

//查看本地时钟和网路时钟差异
kongcb@tcu-Lenovo:~$ ntpdate -d cn.pool.ntp.org
17 May 14:39:36 ntpdate[12707]: ntpdate 4.2.6p5@1.2349-o Wed Oct  9 18:57:00 UTC 2013 (1)
Looking for host cn.pool.ntp.org and service ntp
host found : 111.230.189.174
transmit(111.230.189.174)
receive(111.230.189.174)
transmit(94.237.64.20)    
.......
server 94.237.64.20, port 123
stratum 2, precision -25, leap 00, trust 000
refid [94.237.64.20], delay 0.12453, dispersion 0.00023
transmitted 4, in filter 4
reference time:    e62dbdc3.f523cdc3  Tue, May 17 2022 14:22:59.957
originate timestamp: e62dc0b0.235c07cd  Tue, May 17 2022 14:35:28.138
transmit timestamp:  e62dc1af.3064ec71  Tue, May 17 2022 14:39:43.189
filter delay:  0.12569  0.12532  0.12471  0.12453 
         0.00000  0.00000  0.00000  0.00000 
filter offset: -255.100 -255.100 -255.100 -255.100
         0.000000 0.000000 0.000000 0.000000
delay 0.12453, dispersion 0.00023
offset -255.100391  	//差别有255秒

//同步网络时钟
kongcb@tcu-Lenovo:~$ sudo ntpdate -u cn.pool.ntp.org	//国内时钟服务器
17 May 14:38:23 ntpdate[12737]: adjust time server 202.118.1.81 offset 0.000369 sec
kongcb@tcu-Lenovo:~$ date
20220517日 星期二 14:38:27 CST

ntp常用服务器

//国内
cn.pool.ntp.org  中国开源免费NTP服务器
ntp1.aliyun.com 阿里云NTP服务器
ntp2.aliyun.com 阿里云NTP服务器
time1.aliyun.com 阿里云NTP服务器
time2.aliyun.com 阿里云NTP服务器
//海外
pool.ntp.org 开源免费NTP服务器
time1.apple.com 苹果NTP服务器
time2.apple.com 苹果NTP服务器
time3.apple.com 苹果NTP服务器
time4.apple.com 苹果NTP服务器
time5.apple.com 苹果NTP服务器
time1.google.com 谷歌NTP服务器
time2.google.com 谷歌NTP服务器
time3.google.com 谷歌NTP服务器
time4.google.com 谷歌NTP服务器

linux应用程序时钟操作

接口类型

接口相关头文件
#include <time.h>
相关数据结构体定义:
timespec结构包括:
struct timespec {
	time_t tv_sec; /* 秒*/
	long tv_nsec; /* 纳秒*/
};

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

函数原型:
int clock_gettime(clockid_t clk_id, struct timespec *tp);
其中,cld_id类型有一下几种:   
#define CLOCK_REALTIME			0 //可设定的系统级实时时钟,真实时间度量,可变更
#define CLOCK_MONOTONIC			1//不可设定的恒定态时钟,系统启动不会变,不会随时钟修改跳跃性变化
#define CLOCK_PROCESS_CPUTIME_ID	2//每进程CPU时间的时钟,测量调用进程消耗的用户和系统CPU时间
#define CLOCK_THREAD_CPUTIME_ID		3//每线程CPU时间的时钟,基本同上,不过是进程的时间
#define CLOCK_MONOTONIC_RAW			4//类似MONOTONIC,但不会收NTP影响
#define CLOCK_REALTIME_COARSE		5//同CLOCK_REALTIME,以较小代价获取低分辨率时间戳
#define CLOCK_MONOTONIC_COARSE		6//同CLOCK_MONOTONIC,以较小代价获取低分辨率时间戳
#define CLOCK_BOOTTIME				7//类似MONOTONIC,但系统suspend后依然会增加

注意:对于CLOCK_MONOTONIC时钟,系统启动后置0,之后累加,但也并非不能修改,有几种情况会有修改:
1:时钟的clock-source修改了,比如时钟从高频时钟源转到低频的
2:timezone修改了,如从local time修改为UTC time
不过一般正常操作不会碰到这种情况了,且嵌入式设备系统一般不会配置ntp等等,实际上想操作也不行

获取时钟

struct timespec time;
//获取当前系统时钟秒数
int nRet = clock_gettime(CLOCK_REALTIME_COARSE, &time);
time_t ttSec =  time.tv_sec;

//获取当前时钟毫秒数
int nRet = clock_gettime(CLOCK_REALTIME, &time);
long long llmSec =  time.tv_sec*1000 + time.tv_nsec/1000000;

//获取启动一来的秒数
int nRet = clock_gettime(CLOCK_MONOTONIC_COARSE, &time);
time_t ttSecMon =  time.tv_sec;

//获取启动一来的毫秒数
int nRet = clock_gettime(CLOCK_MONOTONIC, &time);
long long llmSecMonCnt =  time.tv_sec*1000 + time.tv_nsec/1000000;

设置时钟

//设置当前时钟
#include <time.h>
	int stime(time_t *t)	//time_t *t是UTC时间,1970-1-1 00:00:00到设定时间的秒数
//如何将年月日时分秒的数据转化为秒呢,有相关接口

//如下两接口将struct tm转换为1970-1-1 00:00:00到指定时间秒数
       time_t timelocal(struct tm *tm);		//转换为local时区的秒数
       time_t timegm(struct tm *tm);		//转换为UTC时区的秒数

//如下接口将time_t转换为tm
       char *asctime(const struct tm *tm);//tm解析为字符串,如"Wed Jun 30 21:49:08 2022\n"
       char *asctime_r(const struct tm *tm, char *buf);

       char *ctime(const time_t *timep);//转换成字符串形态返回。已经由时区转换成当地时间,字符串格式为“Wed Jun 30 21 :49 :08 2022\n”
       char *ctime_r(const time_t *timep, char *buf);

//如下接口将秒转换为tm时间(UTC时间)
       struct tm *gmtime(const time_t *timep);	//time_t表示的秒转换为tm时间-utc
       struct tm *gmtime_r(const time_t *timep, struct tm *result);
//如下接口将秒转换为tm时间(本地时间)
       struct tm *localtime(const time_t *timep);//time_t表示的秒转换为tm时间-local
//如下接口将struct tm时间转换为秒数
	   time_t mktime(struct tm *tm);//struct tm表示的时间,转换为1970-1-1 00:00:00到时间的秒

实例代码

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
	struct timespec tstmtime,tsMonTime;
	struct tm *pCurTime;
	time_t ttSec, ttSecMonCnt, timet;
	long lmSecCnt;
	int nRet = 0;
	
	//获取当前时间
	nRet = clock_gettime(CLOCK_REALTIME, &tstmtime);
	ttSec =  tstmtime.tv_sec;
	lmSecCnt =  tstmtime.tv_sec*1000 + tstmtime.tv_nsec/1000000;
	
	printf("currtime-time-spec: second:%d, mSec:%ld \n", (int )ttSec, lmSecCnt);
    	//获取系统启动一来的秒
	nRet = clock_gettime(CLOCK_MONOTONIC_COARSE, &tsMonTime);
	ttSecMonCnt =  tsMonTime.tv_sec;
	printf("monotonic second :%d \n", (int )ttSecMonCnt);
	
	//将time_t格式转为struct tm格式
	pCurTime = localtime(&ttSec);
	printf("localtime:%d-%d-%d %02d:%02d:%02d \n", 
		pCurTime->tm_year+1900, 
		pCurTime->tm_mon+1, 
		pCurTime->tm_mday,
		pCurTime->tm_hour,
		pCurTime->tm_min,
		pCurTime->tm_sec);
    	pCurTime = gmtime(&ttSec);
	printf("gmtime:%d-%d-%d %02d:%02d:%02d \n", 
		pCurTime->tm_year+1900, 
		pCurTime->tm_mon+1, 
		pCurTime->tm_mday,
		pCurTime->tm_hour,
		pCurTime->tm_min,
		pCurTime->tm_sec);
		
	timet = mktime(pCurTime);
	printf("mktime-utc:get time_t:%d \n", (int )timet);
	
	pCurTime = localtime(&ttSec);
	timet = mktime(pCurTime);
	printf("mktime-location:get time_t:%d \n", (int )timet);
	
	getchar();
}

执行结果

kongcb@tcu-Lenovo:/home/clou-tcu/kongchengbo/test-code/time$ gcc time-test.c -o timetest
kongcb@tcu-Lenovo:/home/clou-tcu/kongchengbo/test-code/time$ ./timetest                 
currtime-time-spec: second:1652783615, mSec:-778793352 
monotonic second :443800 
localtime:2022-5-17 18:33:35 
gmtime:2022-5-17 10:33:35 
mktime-utc:get time_t:1652754815 
mktime-location:get time_t:1652783615 
如上可知:
1CLOCK_MONOTONIC获取启动依赖的秒数
2:本地时间(我们是北京时间)UTC时间差8小时
3:不同接口操作location time和UTC time
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
第1章 操作系统概述 1 1.1 认识操作系统 1 1.1.1 从使用者角度 1 1.1.2 从程序开发者角度 2 1.1.3 从操作系统在整个计算机系统中所处位置 2 1.1.4 从操作系统设计者的角度 3 1.2 操作系统的发展 4 1.2.1 操作系统的演变 4 1.2.2 硬件的发展轨迹 5 1.2.3 软件的轨迹 6 1.2.4 单内核与微内核操作系统 7 1.3 开放源代码的Unix/Linux操作系统 8 1.3.1 Unix的诞生和发展 8 1.3.2 Linux的诞生 9 1.3.3 操作系统标准POSIX 9 1.3.4 GNU和Linux 9 1.3.5 Linux的开发模式 10 1.4 Linux内核 10 1.4.1 Linux内核的位置 10 1.4.2 Linux内核的作用 11 1.4.3 Linux内核子系统 11 1.5 Linux内核源代码 13 1.5.1 多版本的内核源代码 13 1.5.2 Linux内核源代码的结构 13 1.5.3 Linux内核源代码分析工具 14 习题1 15 第2章 内存寻址 17 2.1 内存寻址简介 17 2.1.1 Intel x86 CPU寻址方式的演变 18 2.1.2 IA32寄存器简介 19 2.1.3 物理地址、虚拟地址及线性地址 21 2.2 分段机制 22 2.2.1 地址转换及保护 24 2.2.2 Linux中的段 24 2.3 分页机制 25 2.3.1 页与页表 25 2.3.2 线性地址到物理地址的转换 28 2.3.3 分页示例 28 2.3.4 页面高速缓存(cache) 29 2.3.5 Linux中的分页机制 30 2.4 Linux中的汇编语言 31 2.4.1 AT&T与Intel汇编语言的比较 31 2.4.2 AT&T汇编语言的相关知识 32 2.5 Linux系统地址映射示例 33 习题2 35 第3章 进程 37 3.1 进程介绍 37 3.1.1 程序和进程 37 3.1.2 进程的层次结构 38 3.1.3 进程状态 39 3.1.4 进程实例 40 3.2 进程控制块 41 3.2.1 进程状态 42 3.2.2 进程标识符 43 3.2.3 进程之间的亲属关系 43 3.2.4 进程控制块的存放 44 3.3 进程的组织方式 45 3.3.1 进程链表 45 3.3.2 散列表 46 3.3.3 可运行队列 47 3.3.4 等待队列 47 3.4 进程调度 48 3.4.1 基本原理 48 3.4.2 时间片 50 3.4.3 Linux进程调度时机 50 3.4.4 进程调度的依据 51 3.4.5 调度函数schedule()的实现 52 3.5 进程的创建 54 3.5.1 创建进程 55 3.5.2 线程及其创建 56 3.6 与进程相关的系统调用及其应用 58 3.6.1 fork系统调用 58 3.6.2 exec系统调用 59 3.6.3 wait系统调用 60 3.6.4 exit系统调用 62 3.6.5 进程的一生 63 3.7 与调度相关的系统调用及应用 63 习题3 65 第4章 内存管理 67 4.1 Linux的内存管理概述 67 4.1.1 虚拟内存、内核空间和用户空间 67 4.1.2 虚拟内存实现机制间的关系 69 4.2 进程用户空间的管理 70 4.2.1 进程用户空间的描述 71 4.2.2 进程用户空间的创建 74 4.2.3 虚存映射 76 4.2.4 进程的虚存区示例 76 4.2.5 与用户空间相关的系统调用 78 4.3 请页机制 79 4.3.1 缺页异常处理程序 79 4.3.2 请求调页 81 4.3.3 写时复制 83 4.4 物理内存的分配与回收 83 4.4.1 伙伴算法 85 4.4.2 物理页面的分配 86 4.4.3 物理页面的回收 88 4.4.4 slab分配模式 89 4.4.5 内核空间非连续内存区的分配 93 4.5 交换机制 95 4.5.1 交换的基本原理 95 4.5.2 页面交换守护进程kswapd 99 4.6 内存管理实例 99 4.6.1 相关背景知识 100 4.6.2 代码体系结构介绍 100 4.6.3 实现步骤 103 4.6.4 程序代码 103 习题4 108 第5章 中断和异常 110 5.1 中断的基本知识 110 5.1.1 中断向量 110 5.1.2 外设可屏蔽中断 111 5.1.3 异常及非屏蔽中断 112 5.1.4 中断描述符表 112 5.1.5 相关汇编指令 113 5.2 中断描述符表的初始化 114 5.2.1 IDT表项的设置 114 5.2.2 对陷阱门和系统门的初始化 115 5.2.3 中断门的设置 116 5.3 中断处理 116 5.3.1 中断和异常的硬件处理 116 5.3.2 中断请求队列的建立 117 5.3.3 中断处理程序的执行 119 5.3.4 从中断返回 121 5.4 中断的下半部处理机制 121 5.4.1 为什么把中断分为两部分来处理 122 5.4.2 小任务机制 122 5.4.3 下半部 124 5.4.4 任务队列 125 5.5 中断应用——时钟中断 125 5.5.1 时钟 125 5.5.2 时钟运作机制 126 5.5.3 Linux的时间系统 127 5.5.4 时钟中断处理程序 128 5.5.5 时钟中断的下半部处理 129 5.5.6 定时器及其应用 129 习题5 132 第6章 系统调用 133 6.1 系统调用与应用编程接口、系统命令、内核函数的关系 133 6.1.1 系统调用与API 133 6.1.2 系统调用与系统命令 134 6.1.3 系统调用与内核函数 134 6.2 系统调用处理程序及服务例程 135 6.2.1 初始化系统调用 136 6.2.2 system_call()函数 136 6.2.3 参数传递 137 6.2.4 跟踪系统调用的执行 139 6.3 封装例程 140 6.4 添加新系统调用 141 6.5 实例——利用系统调用实现一个调用日志收集系统 143 6.5.1 代码体系结构 143 6.5.2 把代码集成到内核中 146 6.5.3 实现步骤 148 习题6 148 第7章 内核中的同步 149 7.1 临界区和竞争状态 149 7.1.1 临界区举例 149 7.1.2 共享队列和加锁 150 7.1.3 确定保护对象 151 7.1.4 死锁 152 7.1.5 并发执行的原因 153 7.2 内核同步方法 153 7.2.1 原子操作 153 7.2.2 自旋锁 155 7.2.3 信号量 156 7.3 并发控制实例 157 7.3.1 内核任务及其并发关系 158 7.3.2 实现机制 158 7.3.3 关键代码解释 162 7.3.4 实现步骤 163 习题7 164 第8章 文件系统 165 8.1 Linux文件系统基础 165 8.1.1 Linux文件结构 165 8.1.2 Linux文件系统 166 8.1.3 文件类型 167 8.1.4 文件访问权限 168 8.2 虚拟文件系统 168 8.2.1 虚拟文件系统的引入 168 8.2.2 VFS中的数据结构 170 8.2.3 VFS超级块数据结构 171 8.2.4 VFS的索引节点 173 8.2.5 目录项对象 174 8.2.6 与进程相关的文件结构 176 8.2.7 主要的数据结构之间的关系 179 8.3 文件系统的注册、安装与卸载 180 8.3.1 文件系统的注册和注销 180 8.3.2 文件系统的安装 181 8.3.3 文件系统的卸载 183 8.4 页缓冲区 183 8.4.1 address_space对象 183 8.4.2 address_space对象的操作函数表 184 8.5 文件的打开与读写 185 8.5.1 打开文件 185 8.5.2 读写文件 187 8.6 编写一个文件系统 189 8.6.1 Linux文件系统的实现要素 189 8.6.2 什么是romfs文件系统 191 8.6.3 romfs文件系统的布局与文件结构 191 8.6.4 具体实现的对象 192 习题8 195 第9章 设备驱动 196 9.1 概述 196 9.2 设备驱动程序基础 198 9.2.1 I/O端口 199 9.2.2 设备文件 200 9.2.3 中断处理 201 9.2.4 设备驱动程序框架 203 9.3 字符设备驱动程序 204 9.3.1 字符设备驱动程序的注册 204 9.3.2 简单的字符设备驱动程序示例 205 9.4 块设备驱动程序 208 9.4.1 块设备驱动程序的注册 209 9.4.2 块设备请求 212 习题9 215 附录A 内核中的链表 216 A.1 链表数据结构简介 216 A.2 内核链表数据结构的定义及初始化 217 A.3 操作链表的接口 218 A.4 遍历链表 219 附录B 内核模块 221 B.1 什么是模块 221 B.2 编写一个简单的模块 221 B.3 模块编程的基础知识 222 B.4 模块的编译 224 B.5 模块实用程序modutils 226 附录C Linux内核编译 228 C.1 内核简介 228 C.2 为什么重新编译内核 228 C.3 内核编译模式 229 C.4 新版本内核的获取和更新 229 C.5 内核编译 230 C.6 修改并重启管理器 232 附录D Linux编程基础(C语言环境) 233 D.1 Linux编程常识 233 D.1.1 相关标准(ANSI C、POSIX、SVID、XPG) 233 D.1.2 函数库和系统调用 234 D.1.3 在线文档(man、info、HOWTO) 235 D.1.4 C语言编程风格 237 D.2 Linux上的C/C++编译器和调试器 238 D.2.1 运行gcc/egcs 238 D.2.2 gcc/egcs的主要选项 240 D.2.3 gdb简介 240 D.2.4 gdb的常用命令 241 D.2.5 gdb使用示例 242 D.3 GNU make和makefile 243 D.3.1 GNU make 243 D.3.2 makefile的基本结构 243 D.3.3 makefile的变量 244 D.3.4 GNU make的主要预定义变量 245 D.3.5 GNU make的隐含规则 245 D.3.6 运行make 246

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术的微光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值