当前位置: 首页 > news >正文

40 C 语言日期与时间函数详解:time、ctime、difftime、clock(含 UTC/本地时间转换)

1 UTC 时间与本地时间

1.1 UTC 时间

  • 定义:UTC(Coordinated Universal Time,协调世界时)是全球统一的时间标准,以原子钟的高精度计时为基础,独立于地球自转。
  • 特点:
    • 不受地理位置或时区影响,是全球各时区统一参考的时间基准
    • 通过引入闰秒(每年最多增加或减少 1 秒)进行调整,以补偿地球自转速度的微小变化。
    • 确保与基于地球自转的天文时间(UT1)之间的偏差不超过 0.9 秒。
  • 示例2025-05-20 17:20:00 UTC 表示全球统一的时间点。

1.2 本地时间

  • 定义:本地时间(Local Time) 是指将协调世界时(UTC)根据所在时区的偏移量进行调整后的时间,用于满足日常生活中对时间显示和使用的需求。
  • 时区(Time Zone):
    • 全球被划分为 24 个主要时区,相邻时区之间通常相差 1 小时
    • 部分国家或地区采用 30 分钟或 45 分钟 的非整点时区偏移,如印度(UTC+5:30)、尼泊尔(UTC+5:45)
    • 时区通常以 UTC+X 或 UTC−X 的形式表示:
      • UTC+8(如北京时间)表示比 UTC 快 8 小时
      • UTC−5(如美国东部标准时间)表示比 UTC 慢 5 小时
  • 夏令时(Daylight Saving Time, DST):
    • 某些地区在夏季实行夏令时,通常将时间提前 1 小时(把钟表的时间从当前时间向后调快 1 小时),以更好地利用自然光照,节约能源
    • 夏令时的开始与结束时间因国家和地区而异,可能导致本地时间与 UTC 的偏移在一年中发生临时变化。
  • 示例:假设当前 UTC 时间为:2025-05-20 12:00:00
    • 北京(UTC+8) 的本地时间为:2025-05-20 20:00:00
    • 纽约(UTC−5,非夏令时期间) 的本地时间为:2025-05-20 07:00:00

1.3 UTC 与本地时间的转换

  • 转换公式:
    • 本地时间 = UTC 时间 + 时区偏移量(需考虑是否启用夏令时)
    • UTC 时间 = 本地时间 - 时区偏移量(需考虑是否启用夏令时)
  • 示例:
    • 若北京时间(UTC+8,非夏令时)为 2025-05-20 10:00:00,则对应的 UTC 时间为:
      • UTC 时间 = 10:00 - 8 = 02:00,即 2025-05-20 02:00:00
    • 若 UTC 时间为 2025-05-20 12:00:00,则纽约时间(UTC-5,非夏令时)为:
      • 本地时间 = 12:00 + (-5) = 07:00,即 2025-05-20 07:00:00

1.4 时间戳

  • 定义:时间戳(Timestamp)通常表示自 1970 年 1 月 1 日 00:00:00 UTC(称为 Unix 纪元)以来经过的秒数
  • 特点:
    • 是 UTC 时间的一种数值化表示形式,不依赖于任何时区
    • 便于程序进行时间的比较、存储和计算。

2 time() 函数

2.1 函数原型

#include <time.h>  // 必须包含此头文件才能使用 time() 函数time_t time(time_t *timer);

2.2 功能说明

        time() 函数用于获取当前的日历时间(即从 1970 年 1 月 1 日 00:00:00 UTC 开始经过的秒数,不包括闰秒),并将其作为 time_t 类型的值返回

        time_t 类型通常是一个长整型(如 long long long),用于表示时间戳(秒数)。在 printf 中输出时,常用 %ld 或 %lld 作为占位符,具体取决于平台。最常用写法(搭配强制转换):printf("%ld", (long)now) 

  • 参数:
    • timer:一个指向 time_t 类型变量的指针
      • 如果该参数不为 NULL,则当前时间也会被存储到该指针指向的变量中
      • 若为 NULL,则仅返回时间值
  • 返回值:
    • 成功时返回当前的时间值(以秒为单位的 time_t 类型)
    • 如果失败(例如系统无法获取当前时间),返回 (time_t)(-1)

2.3 注意事项

  1. 精度限制:time() 的精度是秒级,不能获取毫秒或微秒级别的时间
  2. 跨平台兼容性:time() 是标准 C 库函数,在所有支持 C 标准库的平台上都可用
  3. 避免频繁调用:虽然性能通常不是问题,但在高并发或实时系统中应谨慎使用
  4. 错误处理:虽然很少发生错误,但建议检查返回值是否为 (time_t)-1

2.4 应用场景

  1. 记录日志时间戳:用于生成带有时间信息的日志内容。
  2. 程序运行计时:可以结合两次调用 time() 来计算程序执行时间(适用于秒级精度)。
  3. 超时判断:用于判断某个操作是否在规定时间内完成。
  4. 文件/数据有效期控制:如生成带有时效性的缓存文件或令牌。
  5. 用户界面显示时间:在 GUI 或 CLI 中显示当前日期和时间。
  6. 生成唯一标识符:基于时间戳生成简单的唯一 ID(注意重复风险)。

2.5 示例程序

#include <stdio.h>
#include <time.h> // 必须包含此头文件才能使用 time() 函数int main()
{time_t current_time; // 声明一个 time_t 类型的变量来存储当前时间戳// 情况 1:参数为 NULL,仅返回当前时间值time_t returned_time = time(NULL);// 可选的检查返回值if (returned_time == (time_t)-1){printf("无法获取当前时间(参数为 NULL 的情况)。\n");}else{printf("情况1(参数为 NULL):当前时间戳:%ld\n", (long)returned_time);}// 情况 2:参数为非 NULL,当前时间会被存储到指针指向的变量中time(&current_time); // 传入变量的地址,将当前时间戳存储到该变量中// 一般不检查返回值,直接使用printf("情况2(参数为非 NULL):当前时间戳:%ld\n", (long)current_time);return 0;
}

        程序在 VS Code 中的运行结果如下所示:


3 ctime() 函数

3.1 函数原型

#include <time.h>  // 必须包含此头文件才能使用 ctime() 函数char *ctime(const time_t *timer);

3.2 功能说明

        ctime() 函数用于将 time_t 类型表示的时间值(即时间戳)转换为一个可读性良好的字符串形式,返回的是一个表示本地时间的字符串

  • 参数:
    • timer:指向一个 time_t 类型变量的指针,表示要转换的时间值
  • 返回值:
    • 成功时返回一个指向静态字符数组的指针,该数组中保存了格式化后的时间字符串
    • 如果失败(如传入的 timer 为 NULL 或系统内部错误),则返回 NULL

3.3 注意事项

  1. 自动换行符:返回的字符串末尾包含一个 \n 换行符
  2. 结果不可修改:返回的字符串是只读的,不应尝试修改其内容
  3. 依赖系统本地时区:ctime() 返回的是本地时间,受操作系统时区设置影响
  4. 返回值需检查:虽然很少失败,但应检查是否为 NULL

3.4 应用场景

  1. 打印当前时间:快速输出程序运行时的当前时间。
  2. 日志记录:在日志信息前加上可读的时间戳。
  3. 调试辅助:在调试过程中查看当前时间。
  4. 简单时间显示:适用于不需要自定义格式的界面或控制台输出。

3.5 示例程序

#include <stdio.h>
#include <time.h> // 必须包含此头文件才能使用 time() 和 ctime() 函数int main()
{time_t current_time; // 声明一个 time_t 类型的变量来存储当前时间戳// 情况 1:参数为 NULL,仅返回当前时间值time_t returned_time = time(NULL);// 可选的检查返回值if (returned_time == (time_t)-1){printf("无法获取当前时间(参数为 NULL 的情况)。\n");}else{printf("情况1(参数为 NULL):当前时间戳:%ld\n", (long)returned_time);// 使用 ctime 输出可读时间字符串printf("情况1 对应的本地时间:%s", ctime(&returned_time)); // 不需要换行符,ctime() 函数会自动添加}// 情况 2:参数为非 NULL,当前时间会被存储到指针指向的变量中time(&current_time); // 传入变量的地址,将当前时间戳存储到该变量中printf("情况2(参数为非 NULL):当前时间戳:%ld\n", (long)current_time);// 使用 ctime 输出可读时间字符串printf("情况2 对应的本地时间:%s", ctime(&current_time)); // 不需要换行符,ctime() 函数会自动添加return 0;
}

        程序在 VS Code 中的运行结果如下所示:


    4 difftime() 函数

    4.1 函数原型

    #include <time.h>  // 必须包含此头文件才能使用 difftime() 函数double difftime(time_t time2, time_t time1);

    4.2 功能说明

            difftime() 函数用于计算两个时间点之间的时间差(以秒为单位)。这两个时间点通常是由 time() 函数获取的 time_t 类型的时间戳

    • 参数:
      • time2:结束时间,一个 time_t 类型值
      • time1:开始时间,一个 time_t 类型值
    • 返回值:
      • 返回 time2 - time1 的差值,结果以 double 类型表示,单位为秒
      • 如果 time2 比 time1 小(即结束时间早于开始时间),则返回负数

    4.3 注意事项

    1. 返回值为 double:可以表示非整数秒的时间差(如某些系统支持更高精度时间),适合更精确的计时
    2. 顺序影响结果:difftime(time2, time1) 表示从 time1 到 time2 的时间差,注意参数顺序
    3. 常用于性能测试:适用于粗略测量代码执行时间(如秒级或亚秒级)
    4. 可以跨时区比较:时间戳本质上是 UTC 时间,不受本地时区影响,因此适合用于跨时区的时间差计算

    4.4 应用场景

    1. 程序运行时间统计:记录某段代码执行前后的时间戳,并计算耗时。
    2. 超时控制:判断某个操作是否在规定时间内完成。
    3. 用户行为分析:记录用户操作之间的间隔时间。
    4. 日志记录:输出事件发生的时间间隔,便于后续分析。
    5. 定时任务调度:用于判断是否满足触发条件。

    4.5 示例程序

    #include <stdio.h>
    #include <time.h> // 必须包含此头文件才能使用 time() 和 difftime() 函数int main()
    {time_t start_time, end_time; // 定义两个 time_t 变量用于保存时间戳printf("程序开始计时...\n");start_time = time(NULL); // 获取开始时间// 模拟耗时操作(通过循环延时)for (unsigned long long i = 0; i < 10000000000LL; ++i); // 简单延迟end_time = time(NULL); // 获取结束时间// 使用 difftime 计算时间差double elapsed_seconds = difftime(end_time, start_time);printf("程序结束计时。\n");printf("经过的时间:%lf 秒\n", elapsed_seconds);return 0;
    }

            程序在 VS Code 中的运行结果如下所示:


    5 clock() 函数

    5.1 函数原型

    #include <time.h>  // 必须包含此头文件才能使用 clock() 函数clock_t clock(void);

    5.2 功能说明

            clock() 函数返回自程序启动以来(或程序进入当前状态以来)的处理器时间(CPU 时间),单位通常是 “时钟滴答”(clock ticks)。该时间以 clock_t 类型表示,通常用于测量一段代码的 CPU 执行时间。

    • 返回值:
      • 返回当前进程使用的处理器时间(CPU 时间),单位为 CLOCKS_PER_SEC(每秒的时钟滴答数),而不是秒数
        • 示例:如果 CLOCKS_PER_SEC 是 1000000,则 clock() 返回的值除以 1000000 可以得到秒数。
        • 因此,clock() 返回的滴答数除以 CLOCKS_PER_SEC 可以得到以秒为单位的 CPU 时间
      • 返回 (clock_t)(-1)(通常是 -1),并可能设置 errno(但标准未明确要求设置 errno,具体行为依赖实现)

    5.3 注意事项

    1. 仅限于当前进程:只能用于测量当前进程内的 CPU 使用情况
    2. 精度问题:在某些系统上,CLOCKS_PER_SEC 的值可能较低(如 100),导致 clock() 的分辨率不高,适合粗略估计而非高精度计时
    3. 平台差异性:不同操作系统实现可能有所不同,尤其注意 CLOCKS_PER_SEC 的值
    4. 返回类型:返回类型是 clock_t,需根据具体平台将其转换为秒(除以 CLOCKS_PER_SEC)或其他时间单位进行解释

    5.4 应用场景

    1. 性能分析:评估特定算法或代码段的执行效率。
    2. 调试辅助:帮助开发者了解某部分代码是否耗时过长。
    3. 资源监控:监测程序运行过程中对 CPU 资源的占用情况。
    4. 测试工具开发:构建自动化测试框架中的一部分,用于度量测试案例的执行速度。

    5.5 示例程序

    #include <stdio.h>
    #include <time.h> // 必须包含此头文件才能使用 clock() 函数int main()
    {// 记录开始时间clock_t start_time = clock();// 模拟一个耗时的操作for (unsigned long long i = 0; i < 10000000000LL; ++i); // 简单延迟// 记录结束时间clock_t end_time = clock();// 计算消耗的 CPU 时间,并将其转换为秒(除以 CLOCKS_PER_SEC)double cpu_time_used = ((double)(end_time - start_time)) / CLOCKS_PER_SEC;printf("模拟操作消耗的 CPU 时间: %lf 秒\n", cpu_time_used);return 0;
    }

            程序在 VS Code 中的运行结果如下所示:


    6 日期与时间函数总结

    函数名功能参数返回值
    time获取当前时间戳(自 1970-01-01 00:00:00 UTC 起经过的秒数)time_t *timer:可为 NULL,用于接收时间戳成功返回时间戳(time_t 类型),失败返回 (time_t)-1
    ctime将时间戳转换为可读的本地时间字符串(格式固定,带换行符)const time_t *timer:指向时间戳的指针成功返回指向静态字符串的指针,失败返回 NULL
    difftime计算两个时间点之间的时间差(以秒为单位)time_t time2, time_t time1:两个时间点返回 time2 - time1 的差值(double 类型,单位为秒)
    clock获取当前进程使用的 CPU 时间(从程序启动开始计算)无参数成功返回 CPU 使用时间(以时钟周期为单位),失败返回 (clock_t)-1

    补充说明:

    • time_t 类型:通常为长整型(如 long 或 long long),用于表示自 Unix 纪元(1970-01-01 00:00:00 UTC)以来经过的秒数,即时间戳
    • ctime() 的线程安全性该函数返回一个指向内部静态缓冲区的指针,内容在每次调用时会被覆盖
    • difftime() 的优势:该函数基于标准 C 定义,能够准确计算两个时间点之间的差值,单位为秒(支持小数),适用于跨平台、跨时区的时间差比较,是推荐的标准方法
    • clock() 的局限性:它返回的是程序所占用的 CPU 时间,而非真实世界时间(wall-clock time),因此不适合用于测量 I/O 操作、睡眠或等待外部事件的时间
    http://www.xdnf.cn/news/992359.html

    相关文章:

  • PostGIS实现波段添加导入【ST_AddBand】
  • Linux相关问题整理
  • 如何利用智能助手提升工作效率:从入门到实践
  • C语言学习20250611
  • Docker容器技术介绍,应用场景,安装应用以及项目部署
  • AUTOSAR图解==>AUTOSAR_TR_ModelingShowCases
  • D. Plus Minus Permutation
  • day28/60
  • 常用的免费网络API接口
  • 脑机新手指南(九):高性能脑文本通信:手写方式实现(上)
  • 【navigator.clipboard】复制链接弹出详情信息(模拟电商app)、页面中粘贴图片、复制文本自动添加版权信息
  • CentOS7自带的yum依然无法联网到官方源
  • 自我推荐一下
  • 关于亚马逊WOOT折扣力度
  • 中国北方GNSS业务站网积雪深度数据集(GSnow-CHINA v1.0, 12h/24h, 2013-2...
  • 【烧脑算法】三指针的降维打击:三线并行锁定解题细节
  • 数据隐私是什么?如何做好数据隐私规范?
  • Nuttx之mm_extend
  • Python数据类型大全:整型、浮点、字符串与布尔值
  • Codeforces 1029 Div3(ABCDE)
  • Windows10下利用VS2019编译JpegLib
  • seo优化新利器:AI如何让内容批量生成与排名提升双管齐下?
  • Gremlin创建schema(包括实体和关系)
  • 【质数】埃氏筛法、线性筛法(欧拉筛法)
  • 【Linux系统编程】System V
  • Java锁机制对决:ReadWriteLock vs StampedLock
  • 从0到1落地一个RAG智能客服系统
  • ConcurrentHashMap详解:原理、实现与并发控制
  • 专访伦敦发展促进署CEO:在AI与黄仁勋之外,伦敦为何给泡泡玛特和比亚迪留了C位?
  • MySQL优化器