C语言 <time.h> 头文件详解

C语言 time.h 头文件详解

  • 一、头文件详解
    • [1. 引言](#1. 引言)
    • [2. 核心类型](#2. 核心类型)
      • [2.1 `time_t`](#2.1 time_t)
      • [2.2 `struct tm`](#2.2 struct tm)
      • [2.3 `clock_t`](#2.3 clock_t)
    • [3. 常用函数](#3. 常用函数)
      • [3.1 `time()` --- 获取当前时间](#3.1 time() — 获取当前时间)
      • [3.2 `localtime()` 与 `gmtime()` --- 时间转换](#3.2 localtime() 与 gmtime() — 时间转换)
      • [3.3 `strftime()` --- 格式化时间输出](#3.3 strftime() — 格式化时间输出)
      • [3.4 `mktime()` --- 将 `struct tm` 转回 `time_t`](#3.4 mktime() — 将 struct tm 转回 time_t)
      • [3.5 `difftime()` --- 计算时间差](#3.5 difftime() — 计算时间差)
      • [3.6 `clock()` --- 测量处理器时间](#3.6 clock() — 测量处理器时间)
      • [3.7 `asctime()` 与 `ctime()` --- 简单字符串输出](#3.7 asctime() 与 ctime() — 简单字符串输出)
    • [4. 综合示例:完整的日期时间工具](#4. 综合示例:完整的日期时间工具)
    • [5. 注意事项](#5. 注意事项)
    • [6. 总结](#6. 总结)
  • 二、代码示例

一、头文件详解

1. 引言

在 C 语言的标准库中,<time.h> 头文件提供了处理日期和时间的函数与类型。无论是记录程序运行耗时、生成时间戳,还是格式化输出当前时间,<time.h> 都是开发者不可或缺的工具。本文将系统讲解 <time.h> 中的核心类型、常用函数以及实际应用示例,帮助你彻底掌握 C 语言中的时间处理。

2. 核心类型

<time.h> 中定义了若干与时间相关的数据类型,理解它们是使用时间函数的前提。

2.1 time_t

time_t 是一个算术类型(通常是 long 或 long long),用于表示从 1970 年 1 月 1 日 00:00:00 UTC(Unix 纪元)起经过的秒数。它是最基础的时间表示形式。

c 复制代码
#include <time.h>

time_t now;
now = time(NULL);  // 获取当前时间(秒数)

2.2 struct tm

struct tm 是一个结构体,将时间拆分为年、月、日、时、分、秒等可读字段,便于程序直接访问。

c 复制代码
struct tm {
    int tm_sec;    // 秒(0-59)
    int tm_min;    // 分(0-59)
    int tm_hour;   // 时(0-23)
    int tm_mday;   // 日(1-31)
    int tm_mon;    // 月(0-11,0 表示一月)
    int tm_year;   // 年(自 1900 起的年数)
    int tm_wday;   // 星期(0-6,0 表示星期日)
    int tm_yday;   // 一年中的第几天(0-365)
    int tm_isdst;  // 夏令时标志
};

注意:tm_mon 从 0 开始,tm_year 从 1900 开始,使用时需要相应调整。

2.3 clock_t

clock_t 用于表示处理器时钟计时单元(clock ticks),通常配合 clock() 函数测量程序运行时间。

3. 常用函数

3.1 time() --- 获取当前时间

c 复制代码
time_t time(time_t *timer);

返回当前日历时间(秒数)。若 timer 不为 NULL,也会将结果写入该指针指向的变量。

c 复制代码
time_t now = time(NULL);
printf("当前时间戳:%ld\n", (long)now);

3.2 localtime() 与 gmtime() --- 时间转换

c 复制代码
struct tm *localtime(const time_t *timer);  // 转换为本地时间
struct tm *gmtime(const time_t *timer);     // 转换为 UTC 时间

两者都返回指向静态 struct tm 的指针,因此多次调用会覆盖同一块内存。

c 复制代码
time_t now = time(NULL);
struct tm *local = localtime(&now);
printf("本地时间:%d-%02d-%02d %02d:%02d:%02d\n",
       local->tm_year + 1900,
       local->tm_mon + 1,
       local->tm_mday,
       local->tm_hour,
       local->tm_min,
       local->tm_sec);

3.3 strftime() --- 格式化时间输出

c 复制代码
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr);

按照指定格式将 struct tm 格式化为字符串,是输出时间最灵活的方式。

c 复制代码
time_t now = time(NULL);
struct tm *local = localtime(&now);
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local);
printf("格式化时间:%s\n", buffer);

常用格式说明符:

格式符 含义 示例
%Y 四位年份 2026
%m 两位月份(01-12) 09
%d 两位日期(01-31) 23
%H 24 小时制小时(00-23) 11
%M 分钟(00-59) 58
%S 秒(00-59) 27
%A 星期全名 Wednesday
%B 月份全名 September

3.4 mktime() --- 将 struct tm 转回 time_t

c 复制代码
time_t mktime(struct tm *timeptr);

将本地时间表示的 struct tm 转换为 time_t 秒数,同时会规范化字段(如将 tm_mon 溢出自动进位)。

c 复制代码
struct tm t = {0};
t.tm_year = 2026 - 1900;  // 年份从 1900 起算
t.tm_mon = 8;             // 9 月(0 起算)
t.tm_mday = 23;
time_t ts = mktime(&t);
printf("对应时间戳:%ld\n", (long)ts);

3.5 difftime() --- 计算时间差

c 复制代码
double difftime(time_t time1, time_t time0);

返回 time1 - time0 的秒数差,返回类型为 double。

c 复制代码
time_t start = time(NULL);
// 模拟耗时操作
for (volatile int i = 0; i < 100000000; i++);
time_t end = time(NULL);
printf("耗时:%.2f 秒\n", difftime(end, start));

3.6 clock() --- 测量处理器时间

c 复制代码
clock_t clock(void);

返回程序自启动以来消耗的处理器时钟数,除以 CLOCKS_PER_SEC 得到秒数。

c 复制代码
clock_t start = clock();
// 模拟耗时操作
for (volatile int i = 0; i < 100000000; i++);
clock_t end = clock();
printf("CPU 耗时:%.3f 秒\n", (double)(end - start) / CLOCKS_PER_SEC);

3.7 asctime() 与 ctime() --- 简单字符串输出

c 复制代码
char *asctime(const struct tm *timeptr);
char *ctime(const time_t *timer);

两者都返回固定格式的字符串(如 Wed Sep 23 11:58:27 2026),但包含换行符,且线程不安全,建议优先使用 strftime()。

c 复制代码
time_t now = time(NULL);
printf("ctime 输出:%s", ctime(&now));

4. 综合示例:完整的日期时间工具

下面是一个综合示例,演示如何获取当前时间、格式化输出、计算时间差以及将字符串解析为时间戳。

c 复制代码
#include <stdio.h>
#include <time.h>

int main() {
    // 1. 获取当前时间
    time_t now = time(NULL);
    printf("当前时间戳:%ld\n", (long)now);

    // 2. 转换为本地时间并格式化输出
    struct tm *local = localtime(&now);
    char buffer[64];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %A", local);
    printf("本地时间:%s\n", buffer);

    // 3. 计算两个时间点之间的差值
    struct tm t1 = {0}, t2 = {0};
    t1.tm_year = 2026 - 1900;
    t1.tm_mon = 8;
    t1.tm_mday = 23;
    t2.tm_year = 2026 - 1900;
    t2.tm_mon = 8;
    t2.tm_mday = 24;

    time_t ts1 = mktime(&t1);
    time_t ts2 = mktime(&t2);
    printf("两天相差:%.0f 秒\n", difftime(ts2, ts1));

    // 4. 测量代码段执行时间
    clock_t start = clock();
    for (volatile int i = 0; i < 50000000; i++);
    clock_t end = clock();
    printf("循环耗时:%.3f 秒\n", (double)(end - start) / CLOCKS_PER_SEC);

    return 0;
}

5. 注意事项

  • 线程安全 :localtime()、gmtime()、asctime()、ctime() 返回静态内存,多线程环境下应使用 localtime_r()、gmtime_r() 等可重入版本。
  • 时区处理 :localtime() 依赖系统时区设置,跨时区应用需谨慎。
  • 精度限制 :time_t 以秒为单位,高精度计时应使用 <time.h> 的 clock_gettime()(POSIX)或 C11 的 <timespec_get>。
  • 年份范围 :struct tm 的 tm_year 从 1900 起算,32 位 time_t 在 2038 年可能溢出,64 位系统通常无此问题。

6. 总结

<time.h> 提供了从底层时间戳到高层格式化输出的完整时间处理能力。掌握 time_t、struct tm 两种核心类型,以及 time()、localtime()、strftime()、mktime()、difftime()、clock() 等常用函数,就能应对绝大多数 C 语言时间编程需求。建议在实际项目中优先使用 strftime() 进行格式化输出,并注意线程安全与精度问题。

二、代码示例

c 复制代码
#define _CRT_SECURE_NO_WARNINGS

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

int main(void)
{
    SetConsoleOutputCP(CP_UTF8);
    // 1. time_t:Unix时间戳,从1970-01-01 00:00:00 UTC 开始的秒数
    time_t now_ts;
    time(&now_ts);   // 获取当前系统时间戳,等价 now_ts = time(NULL);
    printf("1. 当前Unix时间戳(秒) = %lld\n\n", (long long)now_ts);


    // 2. localtime():时间戳 →【本地时区】struct tm(年月日时分秒)
    struct tm* local_tm_ptr = localtime(&now_ts);
    printf("2. localtime 本地时间:\n");
    printf("   年:%d,月:%d,日:%d  时:%d:%d:%d\n",
        local_tm_ptr->tm_year + 1900,  // tm_year = 年份-1900
        local_tm_ptr->tm_mon + 1,       // tm_mon:0~11 → +1
        local_tm_ptr->tm_mday,
        local_tm_ptr->tm_hour,
        local_tm_ptr->tm_min,
        local_tm_ptr->tm_sec);
    printf("   星期 tm_wday(0=周日):%d,年内第%d天\n\n",
        local_tm_ptr->tm_wday, local_tm_ptr->tm_yday);


    // 3. gmtime():时间戳 →【UTC零时区】struct tm
    struct tm* utc_tm_ptr = gmtime(&now_ts);
    printf("3. gmtime UTC零时区时间:\n");
    printf("   年:%d,月:%d,日:%d  时:%d:%d:%d\n\n",
        utc_tm_ptr->tm_year + 1900,
        utc_tm_ptr->tm_mon + 1,
        utc_tm_ptr->tm_mday,
        utc_tm_ptr->tm_hour,
        utc_tm_ptr->tm_min,
        utc_tm_ptr->tm_sec);


    // 4. strftime() 格式化时间字符串(重点,前面RTDateTime用到)
    char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", local_tm_ptr);
    printf("4. strftime格式化本地时间字符串:%s\n\n", buf);


    // 5. mktime():struct tm → time_t(反向转换!年月日转时间戳)
    struct tm custom_tm = { 0 };
    custom_tm.tm_year = 2026 - 1900;
    custom_tm.tm_mon = 9 - 1;    //9月
    custom_tm.tm_mday = 23;
    custom_tm.tm_hour = 10;
    custom_tm.tm_min = 0;
    custom_tm.tm_sec = 0;

    time_t custom_ts = mktime(&custom_tm);
    printf("5. mktime:2026-09-23 10:00:00 对应的时间戳 = %lld\n\n", (long long)custom_ts);


    // 6. difftime():计算两个time_t之间相差多少秒,返回double
    time_t t1 = time(NULL);
    // 模拟延时,VS用Sleep,linux用sleep
    // Sleep(1000);
    time_t t2 = time(NULL);
    double diff_sec = difftime(t2, t1);
    printf("6. difftime 时间差:%.3f 秒\n\n", diff_sec);


    // ========== 【重要】线程安全版本演示 ==========
    // VS: localtime_s(&tm_safe, &now_ts);
    // RT-Thread/Linux: localtime_r(&now_ts, &tm_safe);
    struct tm tm_safe;
#ifdef _WIN32
    localtime_s(&tm_safe, &now_ts);
#else
    localtime_r(&now_ts, &tm_safe);
#endif
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm_safe);
    printf("7. 可重入安全版本 localtime_s/r:%s\n", buf);

    return 0;
}
相关推荐
C++ 老炮儿的技术栈3 小时前
sizeof操作符
c语言·c++·人工智能·mfc·c
wuminyu3 小时前
ForkJoinPool内部WorkQueue的Lock-Free数组操作以及并发任务窃取原理剖析
java·linux·c语言·jvm·c++
她说彩礼65万4 小时前
C语言 堆区和栈区
java·linux·c语言
小师兄吃牛肉5 小时前
C语言基本语法汇总
c语言
无忧.芙桃6 小时前
C++ 并查集详解:原理、实现与应用
c语言·c++·算法·leetcode
Code_Solitude6 小时前
c语言:二分法的完整补充
c语言·开发语言·算法
水饺编程7 小时前
第1章,[Win32 章节]:Windows 简史
c语言·c++·visual studio
福大大架构师每日一题8 小时前
Rust 1.99.0发布:C 可变参数、裸函数、Cargo 配置、Rustdoc 性能与大量兼容性调整全解析
c语言·开发语言·rust
动词ing8 小时前
【C语言题目练习】算法 整数反转
c语言·开发语言·算法