嵌入式Linux系统编程 — 5.2 Linux系统时间与日期

news2024/10/5 8:53:08

目录

1 了解Linux系统时间

1.1 几种常用的时间

1.2 如何查看几种常用的时间

1.3 Linux 系统中的时间

2 time、gettimeofday获取时间

2.1 time函数

2.2 ​​​​​​​gettimeofday函数:

2.3 示例程序

3 时间转换函数

3.1 ctime与ctime_r函数

3.2 localtime与localtime_r函数

3.3 gmtime和gmtime_r函数

3.4 mktime()函数

3.5 asctime 与asctime_r函数

3.6 strftime 函数

3.7 综合示例

4 设置时间 settimeofday


1 了解Linux系统时间

1.1 几种常用的时间

在正式介绍这些时间、日期相关的系统调用或 C 库函数之前,需要向大家介绍一些时间相关的基本概念,譬如 GMT 时间、 UTC 时间以及时区等。

GMT时间:GMT是格林尼治平均时间,以地球的本初子午线——通过英国伦敦郊区的格林尼治天文台的经线——为基准。GMT是历史上用来确定时间的标准,它不随地球自转速度的变化而调整。

UTC时间:目前国际上用来替代GMT的官方时间标准。UTC使用高精度的原子钟来测量时间,并且可以添加闰秒以保持与地球自转周期的一致性。UTC的主要目的是为了提供一个稳定的时间标准,不受地球自转速度微小变化的影响。

地区时间:实际,世界上不少国家和地区都不严格按时区来计算时间。为了在全国范围内采用统一的时间,一般都把某一个时区的时间作为全国统一采用的时间。例如,我国把首都北京所在的东 8 区的时间作为全国统一的时间,称为北京时间, 北京时间就作为我国使用的本地时间, 譬如我们电脑上显示的时间就是北京时间。

1.2 如何查看几种常用的时间

在 Ubuntu 系统下,可以使用 date 命令查看系统当前的本地时间,可以看到显示出来的字符串后面有一个"CST"字样, CST 在这里其实指的是 China Standard Time(中国标准时间)的缩写,如下所示:

要显示UTC时间,可以使用date -u或者date --utc

1.3 Linux 系统中的时间

"系统时钟"和"实时时钟"

在计算机系统中,"系统时钟"(System Clock)和"实时时钟"(Real Time Clock, RTC)是两种不同类型的时钟,它们有不同的用途和特性:

系统时钟(System Clock):

  • 系统时钟是计算机的主时钟,用于跟踪当前的日期和时间。它通常由操作系统管理,并且可以受到用户设置和网络时间协议(NTP)的影响。
  • 系统时钟可能会因为多种原因(如系统休眠或时间同步)而调整或变化。

实时时钟(Real Time Clock, RTC):

  • 实时时钟是一种独立于主系统的时钟,通常由一个小型电池供电,即使在计算机关机时也能保持时间。RTC用于在系统启动时设置系统时钟,并在系统运行时提供准确的时间参考。
  • RTC通常具有较低的精度,但能够在没有外部电源的情况下保持时间,使其成为记录系统启动时间和维护系统时间连续性的关键组件。

jiffies 的引入

Jiffies是Linux内核中用于时间度量的一个概念,它是一个自系统启动以来的计时器,以固定频率递增。每个jiffy的长度取决于系统的时钟频率,通常在不同系统上会有所不同,但大约相当于几毫秒。Jiffies被用来测量系统的运行时间、调度任务和执行时间相关的计算。由于jiffies与实际时间的秒数不是固定比例,它主要用于内核内部的时间管理,而不是用来获取精确的日期和时间。

2 time、gettimeofday获取时间

timegettimeofday 是两个在Linux系统中用于获取时间的函数,分别定义在 <time.h><sys/time.h> 头文件中。

2.1 time函数

time 函数用于获取自1970年1月1日(UTC)以来经过的秒数,函数原型:

#include <time.h>

time_t time(time_t *t);
  • 如果 t 参数不为 NULLtime 函数还会将当前时间戳复制到 t 指向的位置。
  • 返回值是当前时间的时间戳,如果出现错误,则返回 -1 并设置 errno

2.2 ​​​​​​​gettimeofday函数

time()获取到的时间只能精确到秒,如果想要获取更加精确的时间可以使用系统调用 gettimeofday 来实现, gettimeofday()函数提供微秒级时间精度,函数原型如下所示:

#include <sys/time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);
  • 参数 tv 指向一个 timeval 结构,该结构将被填充当前时间的秒和微秒。
  • 参数 tz 指向一个 timezone 结构,如果提供,它将被填充关于本地时区的信息。

2.3 示例程序

以下是使用 timegettimeofday 函数的示例:

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

int main() {
    // 使用 time 函数获取当前时间戳
    time_t current_time = time(NULL);
    printf("Current UNIX timestamp: %ld\n", current_time);

    // 使用 gettimeofday 函数获取当前的日期和时间
    struct timeval now;
    if (gettimeofday(&now, NULL) == 0) {
        printf("Current date and time: %ld.%06ld\n", now.tv_sec, (long)now.tv_usec);
    } else {
        perror("gettimeofday failed");
    }

    return 0;
}

运行结果如下: 

3 时间转换函数

通过 time()或 gettimeofday()函数可以获取到当前时间点相对于 1970-01-01 00:00:00 +0000(UTC)这个时间点所经过时间(日历时间) ,所以获取得到的是一个时间段的长度,但是这并不利于我们查看当前时间,下面介绍一些系统调用或 C 库函数,通过这些 API 可以将 time()或gettimeofday()函数获取到的秒数转换为利于查看和理解的形式。

3.1 ctime与ctime_r函数

ctime()是一个 C 库函数, 可以将日历时间转换为可打印输出的字符串形式, ctime()函数原型如下所示:

#include <time.h>

char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
  • ctime函数将时间戳(以 time_t 类型表示)转换为一个以null结尾的字符串,格式为"Thu Jan 01 00:00:00 1970\n\0"。这个函数不是线程安全的,因为它只返回一个静态缓冲区的指针。
  • ctime_r函数与 ctime 功能相同,但它是线程安全的,因为它将结果写入由调用者提供的缓冲区 buf,推荐大家使用可重入函数 ctime_r()。

3.2 localtime与localtime_r函数

localtime()函数可以把 time()或 gettimeofday()得到的秒数(time_t 时间或日历时间) 变成一个 struct tm结构体所表示的时间, 该时间对应的是本地时间。 localtime 函数原型如下:

#include <time.h>

struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
  • localtime函数:返回一个指向静态分配的 struct tm 的指针,该结构包含了转换后的本地时间。意味着每次调用 localtime 都会覆盖上一次调用的结果,因此它不是线程安全的。
  • localtime_r函数:接受两个参数,第一个是指向 time_t 的指针,第二个是指向由调用者提供的 struct tm 结构的指针。转换的结果将直接存储在 result 指向的结构中。由于结果存储在调用者提供的存储空间中,因此 localtime_r 可以安全地被多个线程使用,而不会相互干扰。

struct tm 结构体如下所示:

struct tm {
    int tm_sec; /* 秒(0-60) */
    int tm_min; /* 分(0-59) */
    int tm_hour; /* 时(0-23) */
    int tm_mday; /* 日(1-31) */
    int tm_mon; /* 月(0-11) */
    int tm_year; /* 年(这个值表示的是自 1900 年到现在经过的年数) */
    int tm_wday; /* 星期(0-6, 星期日 Sunday = 0、星期一=1…) */
    int tm_yday; /* 一年里的第几天(0-365, 1 Jan = 0) */
    int tm_isdst; /* 夏令时 */
};

3.3 gmtime和gmtime_r函数

gmtimegmtime_r 函数都用于将Linux时间戳转换为UTC的日期和时间,并不是计算机的本地时间,这是 与localtime的唯一区别,函数原型如下所示:

#include <time.h>

struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);

3.4 mktime()函数

mktime()函数与 localtime()函数相反, mktime()可以将使用 struct tm 结构体表示的分解时间转换为 time_t时间(日历时间) ,同样这也是一个 C 库函数,其函数原型如下所示:

#include <time.h>

time_t mktime(struct tm *tm);
  • tm: 需要进行转换的 struct tm 结构体变量对应的指针。

3.5 asctime 与asctime_r函数

asctime()函数与 ctime()函数的作用一样,也可将时间转换为可打印输出的字符串形式,与 ctime()函数的区别在于, ctime()是将 time_t 时间转换为固定格式字符串、而 asctime()则是将 struct tm 表示的分解时间转换为固定格式的字符串。 asctime()函数原型如下所示:

#include <time.h>

char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
  • tm: 需要进行转换的 struct tm 表示的时间。
  • buf: 可重入版本函数 asctime_r 需要额外提供的参数 buf,指向一个缓冲区,用于存放转换得到的字符串。

3.6 strftime 函数

strftime()函数也可以将一个 struct tm 变量表示的分解时间转换为为格式化字符串,并且在功能上比 asctime()和 ctime()更加强大,它可以根据自己的喜好自定义时间的显示格式,strftime()函数原型如下所示:

#include <time.h>

size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
  • s: 指向一个缓存区的指针,该缓冲区用于存放生成的字符串。
  • max: 字符串的最大字节数。
  • format: 这是一个用字符串表示的字段, 包含了普通字符和特殊格式说明符,可以是这两种字符的任意组合。 特殊格式说明符将会被替换为 struct tm 结构体对象所指时间的相应值,

    以下是 strftime 函数的一些常见格式化指令:

%a:星期的缩写名。
%A:星期的全名。

%b:月份的缩写名。

%B:月份的全名。

%c:适合人类阅读的日期和时间。

%d:一个月中的第几天(01-31)。

%H:小时(24小时制,00-23)。

%I:小时(12小时制,01-12)。

%m:月份(01-12)。

%M:分钟(00-59)。

%p:AM或PM。

%S:秒(00-59)。

%Y:四位数的年份。

3.7 综合示例

下面的示例使用 ctime_rlocaltime_rgmtime_rmktimeasctime_rstrftime 函数演示了如何安全地获取当前时间,转换为本地时间、UTC时间,以及如何格式化时间字符串。

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

int main() 
{
    time_t rawtime;
    struct tm result_tm;
    char buffer[26]; // 足够存储 "Wed Jan 03 09:06:15 1984\n\0" 的长度

    // 获取当前时间戳
    time(&rawtime);

    // 使用 ctime_r 安全地转换时间戳为本地时间字符串
    if (ctime_r(&rawtime, buffer) != NULL) {
        printf("Current time (ctime_r): %s", buffer);
    }

    // 使用 localtime_r 安全地转换时间戳为本地tm结构
    if (localtime_r(&rawtime, &result_tm) != NULL) {
        printf("Local time (localtime_r): %d-%02d-%02d %02d:%02d:%02d\n",
               result_tm.tm_year + 1900, result_tm.tm_mon + 1,
               result_tm.tm_mday, result_tm.tm_hour,
               result_tm.tm_min, result_tm.tm_sec);
    }

    // 使用 gmtime_r 安全地转换时间戳为UTC tm结构
    if (gmtime_r(&rawtime, &result_tm) != NULL) {
        printf("UTC time (gmtime_r): %d-%02d-%02d %02d:%02d:%02d\n",
               result_tm.tm_year + 1900, result_tm.tm_mon + 1,
               result_tm.tm_mday, result_tm.tm_hour,
               result_tm.tm_min, result_tm.tm_sec);
    }

    // 使用 mktime 将本地tm结构转换为时间戳
    rawtime = mktime(&result_tm);
    if (rawtime == (time_t)-1) {
        perror("mktime failed");
    } else {
        printf("Time stamp (mktime): %ld\n", rawtime);
    }

    // 使用 asctime_r 安全地转换tm结构为本地时间字符串
    if (asctime_r(&result_tm, buffer) != NULL) {
        printf("Time (asctime_r): %s", buffer);
    }

    // 使用 strftime 格式化日期和时间
    if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &result_tm) > 0) {
        printf("Formatted time (strftime): %s\n", buffer);
    }

    return 0;
}

​​​​​​​运行结果如下:

4 设置时间 settimeofday

settimeofday 是一个在 Linux系统中使用的系统调用,用于设置当前的UTC时间和时钟的微秒部分。函数原型如下:

#include <sys/time.h>

int settimeofday(const struct timeval *tv, const struct timezone *tz);
  • tv:指向 struct timeval 的指针,包含了新的秒和微秒值。
  • tz:指向 struct timezone 的指针,包含了关于时区的信息,比如夏令时的偏移量。如果不需要设置时区,这个参数可以设置为 NULL

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小白学python(第四天)顺序与分支篇

这几天因为个人原因&#xff0c;python篇会更新比较慢&#xff0c;还望大家谅解&#xff0c;那么废话不多说&#xff0c;我们现在就进入正题 顺序篇 这个没啥好说的&#xff0c;就是自上而下&#xff0c;依次执行 分支篇 条件&#xff08;if&#xff09;语句语法格式&#…

Listary(Windows 文件搜索工具)专业版值得购买吗?

说到经典的国货软件&#xff0c;有一款 Win 软件是一定绕不过去的。它就是知名的本地文件搜索工具 Listary&#xff01; 便捷的文件搜索窗口&#xff1b;快捷操作的体验&#xff1b;与系统更匹配的外观设计&#xff1b;更智能的排序和更可靠的索引。 便捷的文件搜索窗口 紧凑…

百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现

百亿级存储架构&#xff1a; ElasticSearchHBase 海量存储架构与实现 尼恩&#xff1a;百亿级数据存储架构起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿…

AI大模型API:驱动人工智能创新的核心引擎

在当今快速发展的人工智能领域&#xff0c;AI大模型API成为了开发者必备的利器。这些API为开发者提供了强大的人工智能模型和算法&#xff0c;使他们能够轻松地构建智能化应用和解决方案。作为开发者&#xff0c;我们可以借助AI大模型API实现自然语言处理、图像识别、声音合成等…

windows电脑使用netsh添加端口转发、设置端口转发和删除端口转发

目录 1. 添加端口转发 2. 查看是否添加成功 3. 设置端口转发 4. 删除端口转发 除查看命令外&#xff0c;其他命令需要以管理员方式运行。 1. 添加端口转发 命令&#xff1a; netsh interface portproxy add v4tov4 listenaddress你的外部IP listenport你的外部端口 conne…

Winform使用Flurl调用WebApi的基本用法

微信公众号“CSharp编程大全"的文章《.NET超简单轻量级的HTTP请求组件Flurl》介绍了便捷构建URL及创建HTTP请求的.NET模块Flurl。与HttpClient相比,Flurl封装的更简捷易用&#xff0c;代码量更少。本文学习并测试基于Fluri调用WebApi的基本用法。   基于Fluri调用WebApi…

DIY智能音箱:基于STM32的低成本解决方案 (附详细教程)

摘要: 本文详细介绍了基于STM32的智能音箱的设计与实现过程&#xff0c;包括硬件设计、软件架构、语音识别、音乐播放等关键技术。通过图文并茂的方式&#xff0c;结合Mermaid流程图和代码示例&#xff0c;帮助读者深入理解智能音箱的工作原理&#xff0c;并提供实际操作指导。…

51单片机第11步_在C语言中插入汇编语言

本章重点介绍如何在C语言中插入汇编语言。要不是有记录&#xff0c;真不知道怎么搞。 /* 你在 Project Workspace窗口中,将光标移到DELAY.c处,点下鼠标右键,选择"Options for file DELAY.c", 点击右边的"Generate Assembler SRC File"和“Assemble SRC …

recogito-js:用于文本注释/图像注释的前端插件

创建批注&#xff1a; 继续批注&#xff1a; 右侧批注列表&#xff1a; 1、功能与应用&#xff1a; 文本注释&#xff1a;recogito-js可以将注释功能添加到网页上&#xff0c;或者作为构建完全自定义注释应用程序的工具箱。图像注释&#xff1a;除了文本注释外&#xff0c;它还…

ros笔记01--初次体验ros2

ros笔记01--初次体验ros2 介绍安装ros2测试验证ros2说明 介绍 机器人操作系统(ROS)是一组用于构建机器人应用程序的软件库和工具。从驱动程序和最先进的算法到强大的开发者工具&#xff0c;ROS拥有我们下一个机器人项目所需的开源工具。 当前ros已经应用到各类机器人项目开发中…

python sklearn机械学习模型-回归

&#x1f308;所属专栏&#xff1a;【机械学习】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您…

可编程定时计数器8253/8254 - 8253入门

时钟-给设备打拍子 概述 在计算机系统中&#xff0c;为了使所有设备之间的通信井然有序&#xff0c;各通信设备间必须有统一的节奏&#xff0c;不能各干各的&#xff0c;这个节奏就被称为定时或时钟 时钟并不是计算机处理速度的衡量&#xff0c;而是一种使设备间相互配合而避…

从需求是如何最终抽象成最基本的传参入参

第一层&#xff1a;出参和入参 用通俗的话讲&#xff0c;就是给客户提供服务的一种方式&#xff0c;需要包含入参和出参 。入口参数就是程序执行时会调用的参数&#xff0c;出口参数就是程序执行完会返回的参数。入参的值是被调函数需要&#xff0c; 出参的值是主调函数需要的…

Suno: AI音乐创作的新时代

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。 ——苏轼 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、什么是Suno?1、Suno2、应用场景 二、如何使用Suno制作音乐&#xff1f;步骤1&#xff1a;注册…

二级建造师(建筑工程专业)考试题库,高效备考!!!

16.在施工合同履行期间发生的变更事项中&#xff0c;属于工程变更的是&#xff08;&#xff09;。 A.质量要求变更 B.分包单位变更 C.合同价款变更 D.相关法规变更 答案&#xff1a;A 解析&#xff1a;工程变更一般是指在工程施工过程中&#xff0c;根据合同约定对施工的…

HarmonyOS Next开发学习手册——单选框 (Radio)

Radio是单选框组件&#xff0c;通常用于提供相应的用户交互选择项&#xff0c;同一组的Radio中只有一个可以被选中。具体用法请参考 Radio 。 创建单选框 Radio通过调用接口来创建&#xff0c;接口调用形式如下&#xff1a; Radio(options: {value: string, group: string})…

Python | 计算位涡平流项

写在前面 最近忙着复习、考试…都没怎么空敲代码&#xff0c;还得再准备一周考试。。。等考完试再慢慢更新了&#xff0c;今天先来浅更一个简单但是使用的python code 在做动力机制分析时&#xff0c;我们常常需要借助收支方程来诊断不同过程的贡献&#xff0c;其中最常见的一…

下属无执行力,领导无能为力?用好这3大法则,打造一流行动力

下属无执行力&#xff0c;领导无能为力&#xff1f;用好这3大法则&#xff0c;打造一流行动力 第一个&#xff1a;漏斗法则 在沟通这个领域&#xff0c;有一个漏斗法则&#xff0c;意思就是指&#xff1a;如果你脑袋里面想表达的是100%&#xff0c;那你说出口的会只有80%&…

【动态规划】139. 单词拆分

139. 单词拆分 难度&#xff1a;中等 力扣地址&#xff1a;https://leetcode.cn/problems/word-break/description/ 问题描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字…

App托管服务分发平台 index-uplog.php 文件上传致RCE漏洞复现

0x01 产品简介 App托管服务分发平台是一个为开发者提供全面、高效、安全的应用程序托管、分发和推广服务的平台。开发者可以将自己开发的应用程序上传到平台上,平台会对上传的应用程序进行审核,确保应用的质量和安全性。平台会根据开发者的要求,将应用分发到不同的应用市场…