# 系统时间 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- # 功能概述 系统时间表示在计算机系统中的时间与日期。通常用系统时钟(System Clock)从某个时间起点的嘀嗒数(Ticks)。 在大部分系统中,时间是不可或缺的一部分,UniRTOS设备有几个时间,支持多种时间信息及时间同步,如硬件时间时钟(RTC)模块、时间(utime)模块、定时器(Timer)模块及时间同步协议NITZ模块和NTP模块。 UniRTOS设备时间功能应用如下图所示: ```{image} images/image_A7XKbks1Ao2euHxUheYcoIuCn0e.webp :width: 1885px :height: 824px :align: center ``` ## RTC 实时时钟(Real-Time Clock,简称RTC)是一种集成电路。系统可以通过RTC建立和保持系统时间,帮助用户获得精确的实时时间,为电子系统提供精确的时间基准。 RTC可以提供独立于操作系统的时间计时服务,即使设备关机(不断电)也能保持时间的准确性。 **RTC ALARM** 闹钟是被设计成会在特定的时间向用户发出讯号的时钟,用来提醒其它事务。 在UniRTOS中,闹钟用于设置RTC到期时间,时间到期就会调用注册的回调函数。该方式也用于低功耗唤醒,在低功耗状态下,通过RTC进行唤醒工作。 ```c // 1. 设置闹钟(60秒后) qosa_rtc_set_alarm(&tm); qosa_rtc_enable_alarm(1); // 2. 进入低功耗睡眠(消耗最少功率) qosa_task_sleep_sec(100); // 睡眠时间 > 闹钟时间 // 3. 60秒后RTC闹钟触发 → 回调函数执行 → 设备唤醒 ``` ## System Tick 系统节拍通常是指CPU时钟,是操作系统的心脏,维持着整个系统运行的稳定性。操作系统要实现时间上的管理,必须依赖于系统节拍。 系统节拍是从开机开始一个不断递增的计数器,其时间精度取决于硬件平台底层的时钟。 **原理** 系统节拍一般由晶振产生,以精确和固定的时间间隔,触发电信号,通过电信号翻转产生一个Tick,设备处理一次数据。比如晶振12MHZ = 12 × 10的6次方,即每秒发出12000000个脉冲信号,那么发出一个脉冲的时间就是时钟周期,也就是1/12微秒。通常也叫做系统时钟周期,是计算机中最基本的、最小的时间单位。 ```{image} images/image_LnjIbS96SoOfJix10ZocKtDxnie.webp :width: 598px :height: 249px ``` **应用** System Tick是系统中最小的时间刻度,因此可以基于此项接口实现高精度时间管理。 ```c QLOGV("===== Measure using System Tick ====="); qosa_uint32_t tick_start = 0; qosa_uint32_t tick_end = 0; qosa_uint32_t tick_diff = 0; // Get start tick tick_start = qosa_get_system_tick_cnt(); // ---- Code to be measured ---- volatile int sum = 0; for (int i = 0; i < 10000; i++) { sum += i; } // --------- End of code --------- // Get end tick tick_end = qosa_get_system_tick_cnt(); // Calculate tick difference tick_diff = tick_end - tick_start; QLOGD("Start tick: %u, End tick: %u", tick_start, tick_end); QLOGD("Tick difference: %u", tick_diff); // Note: To convert tick to milliseconds: // tick_ms = tick_diff * (1000 / CONFIG_QOSA_SYS_TICK_PER_SECOND) // Typical CONFIG_QOSA_SYS_TICK_PER_SECOND = 1000, so 1 tick = 1ms ``` **系统定时器** 相关接口详情,请参考 [定时器应用指导](../%E5%AE%9A%E6%97%B6%E5%99%A8%E5%BA%94%E7%94%A8%E6%8C%87%E5%AF%BC/%E5%AE%9A%E6%97%B6%E5%99%A8%E5%BA%94%E7%94%A8%E6%8C%87%E5%AF%BC.md)。 **时间差** ```c QLOGV("===== Measure in Seconds ====="); qosa_time_t time_start = 0; qosa_time_t time_end = 0; qosa_time_t time_diff = 0; // Get start time (seconds since 1970-01-01) time_start = qosa_get_system_time_seconds(); // ---- Code to be measured ---- // For example, sleep for 2 seconds qosa_task_sleep_sec(2); // --------- End of code --------- // Get end time time_end = qosa_get_system_time_seconds(); // Calculate time difference time_diff = time_end - time_start; QLOGD("Start: %lld s, End: %lld s", time_start, time_end); QLOGD("Code execution time: %lld s (seconds)", time_diff); ``` ```c QLOGV("===== Measure in Milliseconds ====="); qosa_time_t time_start = 0; qosa_time_t time_end = 0; qosa_time_t time_diff = 0; // Get start time (milliseconds since 1970-01-01) time_start = qosa_get_system_time_milliseconds(); // ---- Code to be measured ---- // For example, sleep for 100ms qosa_task_sleep_ms(100); // --------- End of code --------- // Get end time time_end = qosa_get_system_time_milliseconds(); // Calculate time difference time_diff = time_end - time_start; QLOGD("Start: %lld ms, End: %lld ms", time_start, time_end); QLOGD("Code execution time: %lld ms (milliseconds)", time_diff); ``` ```c void example_measure_microseconds(void) { QLOGV("===== Measure in Microseconds ====="); qosa_time_t time_start = 0; qosa_time_t time_end = 0; qosa_time_t time_diff = 0; // Get start time (microseconds since 1970-01-01) time_start = qosa_get_system_time_microseconds(); // ---- Code to be measured ---- // For example, a simple loop volatile int sum = 0; for (int i = 0; i < 1000; i++) { sum += i; } // --------- End of code --------- // Get end time time_end = qosa_get_system_time_microseconds(); // Calculate time difference time_diff = time_end - time_start; QLOGD("Start: %lld us, End: %lld us", time_start, time_end); QLOGD("Code execution time: %lld us (microseconds)", time_diff); } ``` ## UTC时间 UTC时间(Universal Time Coordinated, 世界标准时间或世界协调时间),以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。 全球统一时间,但是由于地球旋转导致不同地域的人看到的日出日落的时间不同,全球同一时间显然不符合各地的作息,因此根据地球的地理位置,人为将地球划分成24个不同的时区。因此在UTC的基础上各地区形成本地时间。 本地时间 = UTC时间 + 时区差,比如北京时区是东八区,领先UTC 8个小时,此时如果想获取北京时间,需要将时区配置到东区即可。 UniRTOS提供了本地时间接口以及时区配置接口,系统默认配置在东八区,如果您处在不同的时区,可以根据自己的需求,配置到您所处位置的时区。 ```c // 对应: utime.setTimeZone(8) qosa_rtc_set_timezone(32); // 32 = 8 * 4(四分之一小时单位) // 对应: utime.localtime() qosa_rtc_get_localtime(&local_time); qosa_rtc_gmtime_r(&local_time, &tm); // 打印: 2026-06-17 23:30:45 (UTC+8) ``` ## 时间同步 所谓时间同步,即要求各点之间的绝对时间相同。在我们生活中可能会遇到,钟表长时间运行后,需要手动对表,防止时间偏差太大。那么长时间设备运行为什么时间会有偏差?在连网设备上是如何进行对时操作呢?在一些场景对各设备间时间一致性要求较高如何处理? 带有时间的设备,都是靠本地时钟源进行控制时间走时,长时间运行时,会受到本身精度或者环境的影响,出现偏差,此时对于时间要求较高的场景下,就需要对设备时间进行同步,保证运行的稳定性,常用的方式通过NTP向标准时间服务器进行时间同步(如全球NTP授时服务器pool.ntp.org),或者向自己设计的时间服务器进行时间同步。 # 系统时间API ## 头文件 *qosa_rtc.h* ## 函数概览 | **函数** | **描述** | | --- | --- | | *qosa_get_system_tick_cnt* | 获取系统内部运行的时钟节拍数(非时间) | | *qosa_get_system_time* | 获取当前系统时间 | | *qosa_get_system_time_seconds* | 获取自1970年1月1日以来的秒数 | | *qosa_get_system_time_milliseconds* | 获取自1970年1月1日以来的毫秒数 | | *qosa_get_system_time_microseconds* | 获取自1970年1月1日以来的微秒数 | ## 函数详解 ### qosa_get_system_tick_cnt - **功能描述** 获取系统内部运行的时钟节拍数(非时间)。 - **函数原型** ```c qosa_uint32_t qosa_get_system_tick_cnt(void) ``` - **参数说明** 无 - **返回值说明** 返回系统内部运行的时钟节拍数 ### qosa_get_system_time - **功能描述** 获取当前系统时间,并存储到 *qosa_time_info_t* 结构体中。 - **函数原型** ```c qosa_bool_t qosa_get_system_time(qosa_time_info_t *time) ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *time* | 输出 | *qosa_time_info_t** | 指向 *qosa_time_info_t* 结构体的指针,用于存储当前系统时间;详见 [*qosa_time_info_t*](../../%E5%A4%96%E8%AE%BE%E4%B8%8E%E9%A9%B1%E5%8A%A8/RTC/RTC.md#qosatimeinfo_t) | - **返回值说明** *QOSA_TRUE*:函数执行成功 *QOSA_FALSE*:函数执行失败 ### qosa_get_system_time_seconds - **功能描述** 获取自1970年1月1日以来的秒数。 - **函数原型** ```c qosa_time_t qosa_get_system_time_seconds(void) ``` - **参数说明** 无 - **返回值说明** 返回自1970年1月1日以来的秒数,*qosa_time_t* 是通过 *typedef* 关键字定义的类型别名,实际对应 *qosa_uint64_t* 无符号64位整型。 ### qosa_get_system_time_milliseconds - **功能描述** 获取自1970年1月1日以来的毫秒数。 - **函数原型** ```c qosa_time_t qosa_get_system_time_milliseconds(void) ``` - **参数说明** 无 - **返回值说明** 返回自1970年1月1日以来的毫秒数,*qosa_time_t* 是通过 *typedef* 关键字定义的类型别名,实际对应 *qosa_uint64_t* 无符号64位整型。 ### qosa_get_system_time_microseconds - **功能描述** 获取自1970年1月1日以来的微秒数。 - **函数原型** ```c qosa_time_t qosa_get_system_time_microseconds(void) ``` - **参数说明** 无 - **返回值说明** 返回自1970年1月1日以来的微秒数,*qosa_time_t* 是通过 *typedef* 关键字定义的类型别名,实际对应 *qosa_uint64_t* 无符号64位整型。 # 应用逻辑流程图 ```{image} images/image_ABzcb9R1voEcU7xxFMgcRPj6nde.webp :width: 1704px :height: 367px :align: center ``` # 示例代码 完整示例代码请查看https://github.com/UniRTOS/UniRTOS-Doc-Examples/blob/main/system/time/time.c # 常见问题 ## 模块关机(不断电),RTC是否还在运行? 在模块上电后,无论模块状态如何(运行模式、低功耗模式、处于复位状态或者关机状态),只要电源电压保持在工作范围内,RTC不会停止工作,之前的时间就不会丢失。