编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

    • Linux应用开发
    • QML基础入门

    • QT核心库实践

      • QT核心库实践
      • 核心功能基础
      • 并发与多线程
      • 文件与IO系统
      • 日期与时间处理
        • 4.1 时间类
          • 4.1.1 QDate
          • 4.1.2 QTime
          • 4.1.3 QDateTime
          • 4.1.4 QTimeZone
        • 4.2 计时器
          • 4.2.1 计时器分类
        • 4.3 QTimer
          • 4.3.1 基本用法
          • 4.3.2 QTimer用法
          • 4.3.3 QTimer作用
          • 4.3.4 QTimer原理
          • 4.3.5 高级用法
        • 4.4 QElapsedTimer
          • 4.4.1 基本用法
          • 4.4.2 常用方法
        • 4.5 QDeadlineTimer
          • 4.5.1 基本用法
          • 4.5.2 常用方法
        • 4.X QDateTime 内部存储与陷阱
          • 时区转换
          • 性能对比
        • 4.6 QDateTime 内部存储与陷阱
          • 4.6.1 内部数据结构
          • 4.6.2 嵌入式时区陷阱
          • 4.6.3 QDateTime 常见错误
        • 4.7 QCalendar 与 QBasicTimer
          • 4.7.1 QCalendar(Qt 5.14+)
          • 4.7.2 QBasicTimer
        • 4.8 嵌入式时间同步与优化
          • 4.8.1 NTP 时间同步策略
          • 4.8.2 定时器合并(Timer Coalescing)
        • 4.9 综合案例
          • 案例:嵌入式设备的时间管理系统
        • 4.10 速查表
      • 网络与序列化
      • QT事件系统
      • 信号与槽机制
      • 多媒体的应用
      • 容器类和算法
      • 高级编程技巧
    • Linux系统编程

    • 综合项目实战

  • IoT智能硬件开发

  • Apps
  • Linux应用开发
  • QT核心库实践
杨充
2025-08-21
目录

日期与时间处理

# 04.日期与时间处理

# 目录介绍

  • 4.1 时间类
    • 4.1.1 QDate
    • 4.1.2 QTime
    • 4.1.3 QDateTime
    • 4.1.4 QTimeZone
  • 4.2 计时器
    • 4.2.1 计时器分类
  • 4.3 QTimer
    • 4.3.1 基本用法
    • 4.3.2 QTimer用法
    • 4.3.3 QTimer作用
    • 4.3.4 QTimer原理
    • 4.3.5 高级用法
  • 4.4 QElapsedTimer
    • 4.4.1 基本用法
    • 4.4.2 常用方法
  • 4.5 QDeadlineTimer
    • 4.5.1 基本用法
    • 4.5.2 常用方法

# 4.1 时间类

Qt 提供了多个类用于处理日期、时间和时区,包括 QDate、QTime、QDateTime 和 QTimeZone。

  • QDate:日期处理
  • QTime:时间处理
  • QDateTime:日期时间处理
  • QTimeZone:时区支持

# 4.1.1 QDate

QDate 用于处理日期(年、月、日),不包含时间信息。

(1)基本用法

#include <QDate>
#include <QDebug>

int main() {
    // 创建日期
    QDate date(2023, 10, 5);
    // 获取日期信息
    qDebug() << "Year:" << date.year();      // 2023
    qDebug() << "Month:" << date.month();    // 10
    qDebug() << "Day:" << date.day();        // 5
    // 格式化日期
    qDebug() << "Formatted date:" << date.toString("yyyy-MM-dd"); // 2023-10-05
    // 计算日期
    QDate nextWeek = date.addDays(7);
    qDebug() << "Next week:" << nextWeek.toString("yyyy-MM-dd"); // 2023-10-12
    return 0;
}

(2)常用方法

  • isValid():检查日期是否有效。
  • daysInMonth():返回当前月份的天数。
  • daysInYear():返回当前年份的天数。
  • dayOfWeek():返回星期几(1 = 星期一,7 = 星期日)。

# 4.1.2 QTime

QTime 用于处理时间(时、分、秒、毫秒),不包含日期信息。

(1)基本用法

#include <QTime>
#include <QDebug>

int main() {
    // 创建时间
    QTime time(14, 30, 45);
    // 获取时间信息
    qDebug() << "Hour:" << time.hour();      // 14
    qDebug() << "Minute:" << time.minute();  // 30
    qDebug() << "Second:" << time.second();  // 45
    // 格式化时间
    qDebug() << "Formatted time:" << time.toString("HH:mm:ss"); // 14:30:45
    // 计算时间
    QTime laterTime = time.addSecs(3600); // 增加 1 小时
    qDebug() << "Later time:" << laterTime.toString("HH:mm:ss"); // 15:30:45
    return 0;
}

(2)常用方法

  • isValid():检查时间是否有效。
  • msecsSinceStartOfDay():返回从当天开始到当前时间的毫秒数。
  • secsTo():计算两个时间之间的秒数差。

# 4.1.3 QDateTime

QDateTime 用于处理日期和时间,结合了 QDate 和 QTime 的功能。

(1)基本用法

#include <QDateTime>
#include <QDebug>

int main() {
    // 创建日期时间
    QDateTime dateTime(QDate(2023, 10, 5), QTime(14, 30, 45));
    // 获取日期和时间信息
    qDebug() << "Date:" << dateTime.date().toString("yyyy-MM-dd"); // 2023-10-05
    qDebug() << "Time:" << dateTime.time().toString("HH:mm:ss");   // 14:30:45
    // 格式化日期时间
    qDebug() << "Formatted datetime:" << dateTime.toString("yyyy-MM-dd HH:mm:ss"); // 2023-10-05 14:30:45
    // 计算日期时间
    QDateTime laterDateTime = dateTime.addDays(1).addSecs(3600); // 增加 1 天和 1 小时
    qDebug() << "Later datetime:" << laterDateTime.toString("yyyy-MM-dd HH:mm:ss"); // 2023-10-06 15:30:45
    return 0;
}

(2)常用方法

  • isValid():检查日期时间是否有效。
  • toTime_t():将日期时间转换为 Unix 时间戳。
  • fromTime_t():从 Unix 时间戳创建日期时间。
  • setTimeZone():设置时区(需要 Qt 5.2 及以上版本)。

# 4.1.4 QTimeZone

QTimeZone 用于处理时区信息,支持全球时区的转换和计算。

(1)基本用法

#include <QDateTime>
#include <QTimeZone>
#include <QDebug>

int main() {
    // 创建时区
    QTimeZone timeZone("America/New_York");
    // 创建日期时间并设置时区
    QDateTime dateTime(QDate(2023, 10, 5), QTime(14, 30, 45), timeZone);
    // 转换为 UTC 时间
    QDateTime utcDateTime = dateTime.toUTC();
    qDebug() << "Local time:" << dateTime.toString("yyyy-MM-dd HH:mm:ss"); // 2023-10-05 14:30:45
    qDebug() << "UTC time:" << utcDateTime.toString("yyyy-MM-dd HH:mm:ss"); // 2023-10-05 18:30:45
    // 获取时区信息
    qDebug() << "Time zone ID:" << timeZone.id(); // America/New_York
    qDebug() << "Time zone offset:" << timeZone.offsetFromUtc(dateTime); // -14400 (秒)
    return 0;
}

(2)常用方法

  • isValid():检查时区是否有效。
  • offsetFromUtc():返回时区与 UTC 的偏移量(秒)。
  • id():返回时区的 ID(如 "America/New_York")。
  • availableTimeZoneIds():返回所有可用的时区 ID。

# 4.2 计时器

# 4.2.1 计时器分类

Qt 提供了多种计时器类,用于实现定时任务、高精度计时和截止时间管理。

  • QTimer:用于定时任务,支持周期性或单次触发。
  • QElapsedTimer:用于高精度计时,适合测量代码执行时间。
  • QDeadlineTimer:用于管理截止时间,适合超时控制。(Qt 6)

# 4.3 QTimer

QTimer 是一个定时器类,用于在指定的时间间隔触发信号。

QTimer 是 Qt 框架中用于定时器功能的核心类,它允许你在指定的时间间隔内触发事件或执行代码。

# 4.3.1 基本用法

#include <QTimer>
#include <QDebug>
#include <QCoreApplication>

class MyClass : public QObject {
    Q_OBJECT

public:
    MyClass(QObject *parent = nullptr) : QObject(parent) {
        // 创建定时器
        QTimer *timer = new QTimer(this);
        // 连接定时器的 timeout 信号到槽函数
        connect(timer, &QTimer::timeout, this, &MyClass::onTimeout);
        // 启动定时器,每隔 1 秒触发一次
        timer->start(1000);
    }

private slots:  
    void onTimeout() {
        qDebug() << "Timer triggered at:" << QTime::currentTime().toString("HH:mm:ss");
    }
};

int main(int argc, char *argv[]){
    QCoreApplication app(argc, argv);
    MyClass myObject;
    return app.exec();
}

# 4.3.2 QTimer用法

  • start(int msec):启动定时器,msec 为时间间隔(毫秒)。
  • stop():停止定时器。
  • setSingleShot(bool singleShot):设置是否为单次触发。
  • isActive():检查定时器是否正在运行。

(1) 基本用法

#include <QTimer>
#include <QDebug>

QTimer *timer = new QTimer(this);

// 连接定时器的 timeout() 信号到槽函数
connect(timer, &QTimer::timeout, this, []() {
    qDebug() << "Timer triggered!";
});

// 启动定时器,每隔 1000 毫秒(1 秒)触发一次
timer->start(1000);

(2) 停止定时器

timer->stop(); // 停止定时器

(3) 单次触发定时器

timer->setSingleShot(true); // 设置为单次触发
timer->start(1000);         // 1 秒后触发一次,然后停止


// 使用静态方法创建单次定时器
QTimer::singleShot(2000, this, {
    qDebug() << "This will run once after 2 seconds";
});

(4) 检查定时器状态

if (timer->isActive()) {
    qDebug() << "Timer is running";
} else {
    qDebug() << "Timer is not running";
}

# 4.3.3 QTimer作用

(1) 定时触发任务:QTimer 可以在指定的时间间隔内触发 timeout() 信号,用于执行周期性任务,例如:

  • 更新 UI。
  • 轮询数据。
  • 执行定时操作。

(2) 单次延迟执行:通过 setSingleShot(true),QTimer 可以用于延迟执行某个任务,例如:

  • 延迟加载数据。
  • 延迟显示提示信息。

(3) 事件驱动:QTimer 依赖于 Qt 的事件循环,因此可以与其他事件驱动的功能无缝集成。

# 4.3.4 QTimer原理

(1) 底层实现:QTimer 基于操作系统的定时器机制(如 Linux 的 timerfd 或 Windows 的 SetTimer)。

  • 在 Qt 的事件循环中,QTimer 会注册一个定时器事件,当时间到达时,事件循环会触发 timeout() 信号。

(2) 事件循环依赖:QTimer 必须运行在 Qt 的事件循环中。如果没有事件循环,定时器将无法工作。例如:

  • 在主线程中,QApplication::exec() 启动了事件循环。
  • 在子线程中,需要调用 QThread::exec()。

(3) 精度问题:QTimer 的精度取决于操作系统和硬件,通常为毫秒级别。

  • 如果需要高精度定时器,可以考虑使用平台特定的 API(如 nanosleep 或 QueryPerformanceCounter)。

# 4.3.5 高级用法

(1) 动态调整定时器间隔

timer->setInterval(500); // 将定时器间隔调整为 500 毫秒

(2) 多定时器管理

如果需要管理多个定时器,可以使用 QTimer 的 timerId() 方法:

int timerId = timer->timerId();

(3) 在子线程中使用 QTimer

在子线程中使用 QTimer 时,需要确保子线程有事件循环:

QThread *thread = new QThread;
QTimer *timer = new QTimer;

timer->moveToThread(thread);

connect(thread, &QThread::started, [timer]() {
    timer->start(1000);
});

connect(timer, &QTimer::timeout, []() {
    qDebug() << "Timer triggered in thread!";
});

thread->start();

# 4.4 QElapsedTimer

QElapsedTimer 用于高精度计时,适合测量代码执行时间。

# 4.4.1 基本用法

#include <QElapsedTimer>
#include <QDebug>
#include <QThread>

int main() {
    QElapsedTimer timer;
    timer.start(); // 开始计时
    // 模拟耗时操作
    QThread::msleep(1000); // 休眠 1 秒
    // 获取经过的时间
    qint64 elapsed = timer.elapsed(); // 毫秒
    qDebug() << "Elapsed time:" << elapsed << "ms";
    // 获取纳秒级时间
    qint64 nsecsElapsed = timer.nsecsElapsed(); // 纳秒
    qDebug() << "Elapsed time in nanoseconds:" << nsecsElapsed << "ns";
    return 0;
}

# 4.4.2 常用方法

  • start():开始计时。
  • elapsed():返回从开始计时到现在的毫秒数。
  • nsecsElapsed():返回从开始计时到现在的纳秒数。
  • hasExpired(qint64 timeout):检查是否已经超过指定的时间(毫秒)。

# 4.5 QDeadlineTimer

QDeadlineTimer 用于管理截止时间,适合需要设置超时时间的场景。

# 4.5.1 基本用法

#include <QDeadlineTimer>
#include <QDebug>
#include <QThread>

int main() {
    // 设置截止时间为 2 秒后
    QDeadlineTimer deadline(2000); // 2000 毫秒
    // 模拟耗时操作
    QThread::msleep(1000); // 休眠 1 秒
    // 检查是否超时
    if (deadline.hasExpired()) {
        qDebug() << "Deadline has expired!";
    } else {
        qDebug() << "Time remaining:" << deadline.remainingTime() << "ms";
    }
    return 0;
}

# 4.5.2 常用方法

  • setRemainingTime(qint64 msec):设置剩余时间(毫秒)。
  • remainingTime():返回剩余时间(毫秒)。
  • hasExpired():检查是否已经超时。
  • isForever():检查是否为无限时间。

# 4.X QDateTime 内部存储与陷阱

# 时区转换

QDateTime dt(QDate(2025, 7, 1), QTime(12, 0, 0), Qt::UTC);
// 内部: m_msecs = 1751371200000 (自1970-01-01 UTC的毫秒数)

dt.toLocalTime();
// → 查zoneinfo: /usr/share/zoneinfo/Asia/Shanghai → +8h
// → 输出 2025-07-01 20:00:00

⚠️ 嵌入式陷阱:如果 /usr/share/zoneinfo 不存在 → toLocalTime() 静默返回 UTC(无错误!)→ 界面显示错误时间

# 性能对比

定时器 底层 精度 是否耦合事件循环
QTimer::singleShot 事件循环 ~5ms 是
QBasicTimer QObject内部 ~1ms 是
QElapsedTimer 硬件时钟 纳秒级 否
QDeadlineTimer futex 毫秒级 否
// QElapsedTimer——不触发系统调用
QElapsedTimer ticker;
ticker.start();
while (running) {
    if (ticker.elapsed() % 100 < 20) process();  // 粗略100ms判断
}
// QDateTime::currentMSecsSinceEpoch() 每次都是 gettimeofday() 系统调用

# 4.6 QDateTime 内部存储与陷阱

# 4.6.1 内部数据结构

Qt 6 中 QDateTime 的核心存储是一个 64 位毫秒值 + 时区偏移:

// QDateTime 内部(简化)
class QDateTime {
    qint64 m_msecs;        // 自 1970-01-01T00:00:00.000 UTC 的毫秒数
    QTimeZone m_timeZone;  // Qt 6 始终存储完整时区信息
    // Qt 5 只存偏移量 → 无法正确表示 DST(夏令时)
};

// 构造过程:
QDateTime dt(QDate(2025, 7, 1), QTime(12, 0, 0), Qt::UTC);
// → m_msecs = (2025-07-01T12:00:00 UTC - 1970-01-01 UTC) = 1751371200000 ms

QDateTime dt(QDate(2025, 7, 1), QTime(12, 0, 0), Qt::LocalTime);
// → m_msecs = 先按 local 转 UTC: 12:00 - 8h = 04:00 UTC
// → m_msecs = 1751342400000 ms

# 4.6.2 嵌入式时区陷阱

// ⚠️ 如果 /usr/share/zoneinfo 不存在:
QDateTime dt = QDateTime::currentDateTime();
dt.toLocalTime();  // 静默返回 UTC——不报错!
// → 界面可能显示错误时间却没有任何警告

// ✅ 防御策略:验证时区
if (QTimeZone::systemTimeZone().isValid()) {
    updateClock();
} else {
    qWarning() << "No timezone data found! Using UTC";
    setTimeZoneFixed(QTimeZone::utc());
}

# 4.6.3 QDateTime 常见错误

// ❌ 错误 1:直接比较不同时区的 QDateTime
QDateTime utc(QDate(2025,7,1), QTime(12,0,0), Qt::UTC);
QDateTime local(QDate(2025,7,1), QTime(20,0,0), Qt::LocalTime); // UTC+8
if (utc == local) {
    // 是否相等?这取决于实现!
    // Qt 6: 默认转换到同一时区比较 → 相等(都是同一时刻)
    // Qt 5: 可能直接比较 m_msecs → 不相等(12:00 vs 20:00)
}

// ✅ 正确:统一转换到 UTC 再比较
if (utc.toUTC() == local.toUTC()) {
    // 始终正确
}

// ❌ 错误 2:对无效 QDateTime 操作
QDateTime dt;  // 默认构造 = 无效
if (dt.isValid()) {
    dt.toString();  // 安全
}

# 4.7 QCalendar 与 QBasicTimer

# 4.7.1 QCalendar(Qt 5.14+)

支持非公历日历系统(农历、伊斯兰历等):

#include <QCalendar>

// 创建农历日期
QCalendar lunarCal = QCalendar(QCalendar::System::Chinese);
QDate lunarDate(2025, 1, 1);  // 公历
QDate chineseDate = lunarCal.dateFromParts(2025, 6, 15);
qDebug() << "Lunar date:" << chineseDate.toString("yyyy-MM-dd");

// QDate 的内置日历支持
QDate today = QDate::currentDate();
qDebug() << "Gregorian:" << today;
qDebug() << "Julian:" << today.toString(Qt::ISODate, QCalendar(QCalendar::System::Julian));

# 4.7.2 QBasicTimer

QBasicTimer 是比 QTimer 更轻量的定时器——不创建 QObject,直接嵌入在类中:

class MyWidget : public QWidget {
    QBasicTimer m_timer;

protected:
    void startAnimation() {
        m_timer.start(16, this);  // ~60 FPS
    }

    void timerEvent(QTimerEvent* event) override {
        if (event->timerId() == m_timer.timerId()) {
            updateAnimation();  // 轻量级帧更新
        }
    }
};

QBasicTimer vs QTimer:

QTimer QBasicTimer
类型 QObject 值类型 POD
使用 信号槽 重写 timerEvent()
开销 信号槽分发 直接函数调用
适合 通用场景 高频定时(>60Hz)

# 4.8 嵌入式时间同步与优化

# 4.8.1 NTP 时间同步策略

class TimeSyncManager : public QObject {
    Q_OBJECT

public:
    void syncWithNTP(const QString& ntpServer) {
        // 方式 1:使用系统命令(嵌入式常见)
        QProcess ntpdate;
        ntpdate.start("ntpdate", {"-u", ntpServer});
        ntpdate.waitForFinished();
        qDebug() << "Time synced:" << ntpdate.readAllStandardOutput();

        // 方式 2:HTTP 时间获取(无 NTP 环境)
        QNetworkAccessManager* mgr = new QNetworkAccessManager(this);
        QNetworkRequest req(QUrl("http://" + ntpServer + "/api/time"));
        QNetworkReply* reply = mgr->get(req);
        connect(reply, &QNetworkReply::finished, [reply]() {
            QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
            qint64 serverTime = doc["timestamp"].toVariant().toLongLong();
            adjustSystemTime(serverTime);
            reply->deleteLater();
        });
    }

    void adjustSystemTime(qint64 utcMsecs) {
        // Linux: settimeofday()
        struct timeval tv;
        tv.tv_sec = utcMsecs / 1000;
        tv.tv_usec = (utcMsecs % 1000) * 1000;
        settimeofday(&tv, nullptr);
    }
};

# 4.8.2 定时器合并(Timer Coalescing)

嵌入式 Linux 内核支持定时器合并——将多个相近的定时器合并为一次唤醒,节省功耗:

传统:Timer1(100ms) Timer2(110ms) Timer3(120ms)
  → 3 次 CPU 唤醒

合并后:
  → 1 次唤醒 @ 110ms(内核自动合并 ±10ms 内的定时器)

// Qt 中启用(需要 Qt 5.13+ 和 Linux 4.20+)
QTimer::coarseTimer  // 粗粒度定时器(合并友好)
// 环境变量:QT_USE_COARSE_TIMER=1

# 4.9 综合案例

# 案例:嵌入式设备的时间管理系统

class DeviceTimeSystem : public QObject {
    Q_OBJECT

public:
    DeviceTimeSystem() {
        // 1. 启动时同步时间
        syncTime();

        // 2. 每分钟检查时钟漂移
        m_driftCheckTimer.setInterval(60000);
        connect(&m_driftCheckTimer, &QTimer::timeout, this, &DeviceTimeSystem::checkDrift);
        m_driftCheckTimer.start();

        // 3. 用于定时任务
        m_schedulerTimer.setInterval(1000);
        connect(&m_schedulerTimer, &QTimer::timeout, this, &DeviceTimeSystem::onTick);
        m_schedulerTimer.start();
    }

    // 获取可靠的当前时间
    QDateTime reliableNow() const {
        // 如果有硬件 RTC,用 RTC 时间 + 单调时钟偏移
        if (m_rtcValid) {
            return m_rtcBase.addMSecs(m_uptimeTimer.elapsed());
        }
        return QDateTime::currentDateTime();
    }

    void scheduleTask(const QTime& timeOfDay, std::function<void()> task) {
        m_scheduledTasks.append({timeOfDay, std::move(task)});
    }

private:
    void onTick() {
        QTime now = QTime::currentTime();
        for (auto& task : m_scheduledTasks) {
            if (qAbs(now.msecsTo(task.time)) < 500) {  // 500ms 宽容度
                task.fn();
            }
        }
    }

    void checkDrift() {
        // 比较系统时间与可靠时间源
        qint64 systemTime = QDateTime::currentMSecsSinceEpoch();
        qint64 reliableTime = reliableNow().toMSecsSinceEpoch();

        if (qAbs(systemTime - reliableTime) > 5000) {  // 漂移 > 5s
            qWarning() << "Clock drift detected:" << (systemTime - reliableTime) << "ms";
            syncTime();  // 重新同步
        }
    }

    void syncTime() {
        // NTP/HTTP 时间同步...
        m_rtcBase = QDateTime::currentDateTime();
        m_uptimeTimer.start();
        m_rtcValid = true;
    }

    struct ScheduledTask {
        QTime time;
        std::function<void()> fn;
    };

    QTimer m_driftCheckTimer;
    QTimer m_schedulerTimer;
    QElapsedTimer m_uptimeTimer;
    QDateTime m_rtcBase;
    bool m_rtcValid = false;
    QList<ScheduledTask> m_scheduledTasks;
};

# 4.10 速查表

类 用途 精度 事件循环依赖
QDate 日期(不含时区) 天 否
QTime 时间(不含日期) 毫秒 否
QDateTime 日期+时间+时区 毫秒 否
QTimeZone 时区管理 秒偏移 否
QTimer 定时任务 ~5ms 是
QBasicTimer 轻量定时器 ~1ms 是
QElapsedTimer 高性能计时 纳秒 否
QDeadlineTimer 截止时间 毫秒 否
QCalendar 非公历日历 天 否

时间处理铁律:

  1. QElapsedTimer 用于性能测量——不触发系统调用,纳秒级
  2. QDateTime 比较前统一转 UTC——避免时区差异导致错误
  3. 嵌入式必须验证 /usr/share/zoneinfo 存在——否则静默返回 UTC
  4. 高频定时用 QBasicTimer——比 QTimer 信号槽少一次分发
  5. 不要在主线程中做 NTP 同步——同步阻塞可能导致 UI 冻结
  6. QTimer::singleShot(0, ...) 是延迟到下一轮事件循环——不是立即执行
  7. 休眠用 QThread::msleep,不要用系统 sleep——前者可与事件循环配合
上次更新: 2026/07/02, 11:21:43
文件与IO系统
网络与序列化

← 文件与IO系统 网络与序列化→

最近更新
01
audit
07-27
02
C++入门教程全章思考题汇编
07-24
03
12.技术团队建设能力
07-21
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式