c语言时间戳从入门到精通

深入理解时间戳:从入门到实践

在编程世界中,时间处理是一个绕不开的话题。时间戳作为时间的一种数字化表示方式,在各种系统中都有着广泛的应用。本文将带你深入理解时间戳的概念、原理和实践应用。

目录


一、什么是时间戳?

1.1 基本概念

时间戳 (Timestamp)是指从 1970年1月1日 00:00:00 UTC (协调世界时)到当前时间的 总秒数(在某些系统中可能是毫秒或微秒)。

c 复制代码
// <font color=#7F8C8D>时间戳示例</font>
<font color=#E67E22>1634567890</font>  // 2021-10-19 02:38:10 UTC
<font color=#E67E22>1678900000</font>  // 2023-03-15 13:06:40 UTC

这个起始时间点被称为 Unix Epoch(Unix纪元),也被称为 POSIX时间。

1.2 为什么选择1970-01-01?
Unix操作系统最早诞生于1970年前后

时间可以表示为一个整数,便于计算和存储

避免了时区带来的复杂性

二、时间戳的数据类型
2.1 time_t 类型

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

int main() {
    time_t timestamp;        // <font color=#7F8C8D>通常是32位或64位整数</font>
    time(&timestamp);        // <font color=#7F8C8D>获取当前时间戳</font>
    
    printf("当前时间戳: <font color=#E67E22>%ld</font>\n", timestamp);
    printf("size_t 大小: <font color=#E67E22>%lu</font> 字节\n", sizeof(time_t));
    
    return 0;
}

2.2 32位 vs 64位时间戳

类型 范围 问题 最后时间
32位 1901-12-13 到 2038-01-19 2038年问题 2038-01-19 03:14:07
64位 几乎无限 ✓ 无 约2900亿年后

2.3 不同精度的时间戳

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

int main() {
    // 1. 秒级时间戳(常用)
    time_t sec_ts = time(NULL);
    printf(" 秒级时间戳: <font color=#E67E22>%ld</font>\n", sec_ts);
    
    // 2. 毫秒级时间戳
    struct timeval tv;
    gettimeofday(&tv, NULL);
    long long ms_ts = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
    printf(" 毫秒级时间戳: <font color=#E67E22>%lld</font>\n", ms_ts);
    
    // 3. 微秒级时间戳
    long long us_ts = tv.tv_sec * 1000000LL + tv.tv_usec;
    printf(" 微秒级时间戳: <font color=#E67E22>%lld</font>\n", us_ts);
    
    // 4. 纳秒级时间戳
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    long long ns_ts = ts.tv_sec * 1000000000LL + ts.tv_nsec;
    printf(" 纳秒级时间戳: <font color=#E67E22>%lld</font>\n", ns_ts);
    
    return 0;
}

三、时间戳的核心操作
3.1 获取当前时间戳

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

int main() {
    // 方法1:直接获取
    time_t t1 = time(NULL);
    
    // 方法2:通过指针参数获取
    time_t t2;
    time(&t2);
    
    // 方法3:获取高精度时间
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    
    printf("🔹 方法1 - 当前时间戳: <font color=#E67E22>%ld</font>\n", t1);
    printf("🔸 方法2 - 当前时间戳: <font color=#E67E22>%ld</font>\n", t2);
    printf("🔹 方法3 - 秒: <font color=#E67E22>%ld</font>, 纳秒: <font color=#E67E22>%ld</font>\n", ts.tv_sec, ts.tv_nsec);
    
    return 0;
}

3.2 时间戳转可读时间

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

void timestamp_to_readable(time_t timestamp) {
    struct tm *tm_info;
    char buffer[30];
    
    // <font color=#3498DB>转换为本地时间</font>
    tm_info = localtime(&timestamp);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" 本地时间: <font color=#2ECC71>%s</font>\n", buffer);
    
    // <font color=#3498DB>转换为UTC时间</font>
    tm_info = gmtime(&timestamp);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" UTC时间:  <font color=#3498DB>%s</font>\n", buffer);
}

int main() {
    // <font color=#F39C12>当前时间戳</font>
    time_t now = time(NULL);
    printf(" 当前时间戳: <font color=#E67E22>%ld</font>\n", now);
    timestamp_to_readable(now);
    
    printf("\n<font color=#9B59B6>--- 指定时间戳示例 ---</font>\n");
    timestamp_to_readable(1678900000);
    timestamp_to_readable(1609459200);  // 2021-01-01 00:00:00
    
    return 0;
}

3.3 可读时间转时间戳

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

time_t readable_to_timestamp(int year, int mon, int day, 
                             int hour, int min, int sec) {
    struct tm tm_info = {0};
    
    tm_info.tm_year = year - 1900;  // 年份从1900开始
    tm_info.tm_mon = mon - 1;        // 月份从0开始
    tm_info.tm_mday = day;
    tm_info.tm_hour = hour;
    tm_info.tm_min = min;
    tm_info.tm_sec = sec;
    tm_info.tm_isdst = -1;           //自动判断夏令时
    
    return mktime(&tm_info);
}

int main() {
    time_t ts;
    
    ts = readable_to_timestamp(2023, 12, 25, 10, 30, 0);
    printf("🎄 2023-12-25 10:30:00 的时间戳: <font color=#E67E22>%ld</font>\n", ts);
    
    ts = readable_to_timestamp(2024, 1, 1, 0, 0, 0);
    printf("🎆 2024-01-01 00:00:00 的时间戳: <font color=#E67E22>%ld</font>\n", ts);
    
    return 0;
}

3.4 时间格式化详解

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

void format_time_examples(time_t timestamp) {
    struct tm *tm_info = localtime(&timestamp);
    char buffer[100];
    
    printf(" 原时间戳: <font color=#E67E22>%ld</font>\n\n", timestamp);
    
    // 常用格式
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf("1. <font color=#3498DB>标准格式</font>: <font color=#2ECC71>%s</font>\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%Y年%m月%d日 %H时%M分%S秒", tm_info);
    printf("2. <font color=#3498DB>中文格式</font>: <font color=#E74C3C>%s</font>\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%Y/%m/%d %I:%M:%S %p", tm_info);
    printf("3. <font color=#3498DB>12小时制</font>: <font color=#9B59B6>%s</font>\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%A, %B %d, %Y", tm_info);
    printf("4. <font color=#3498DB>英文格式</font>: <font color=#F39C12>%s</font>\n", buffer);
    
    strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Z %Y", tm_info);
    printf("5. <font color=#3498DB>完整格式</font>: <font color=#E67E22>%s</font>\n", buffer);
}

int main() {
    time_t now = time(NULL);
    format_time_examples(now);
    
    return 0;
}

strftime 常用格式化符

格式符 含义 示例 范围
%Y 4位年份 2023 0000-9999
%y 2位年份 23 00-99
%m 2位月份 01-12 01-12
%d 2位日期 01-31 01-31
%H 24小时制 00-23 00-23
%I 12小时制 01-12 01-12
%M 分钟 00-59 00-59
%S 00-59 00-59
%p AM/PM AM AM/PM
%A 星期全名 Monday Sunday-Saturday
%a 星期缩写 Mon Sun-Sat
%B 月份全名 January January-December
%b 月份缩写 Jan Jan-Dec
%j 年中的第几天 001-366 001-366
%w 星期几(数字) 0-6 0=周日
%U 年中的第几周 00-53 周日开始
%W 年中的第几周 00-53 周一开始
%Z 时区名称 CST -
%z 时区偏移 +0800 -

四、时间运算
4.1 计算时间差

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

void calculate_time_diff() {
    time_t start, end;
    
    time(&start);
    printf("▶️ 开始时间戳: <font color=#E67E22>%ld</font>\n", start);
    printf("📅 开始时间: <font color=#2ECC71>%s</font>", ctime(&start));
    
    // 模拟耗时操作
    printf("⏳ 等待2秒...\n");
    sleep(2);
    
    time(&end);
    printf(" 结束时间戳: <font color=#E67E22>%ld</font>\n", end);
    printf(" 结束时间: <font color=#2ECC71>%s</font>", ctime(&end));
    
    // 方法1:直接相减
    double diff1 = end - start;
    printf(" 方法1 - 耗时: <font color=#E74C3C>%.0f</font> 秒\n", diff1);
    
    // 方法2:使用difftime函数
    double diff2 = difftime(end, start);
    printf("方法2 - 耗时: <font color=#E74C3C>%.0f</font> 秒\n", diff2);
}

int main() {
    calculate_time_diff();
    return 0;
}

4.2 时间加减操作

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

void time_add_subtract() {
    time_t now = time(NULL);
    struct tm *tm_info;
    char buffer[30];
    
    printf(" 当前时间戳: <font color=#E67E22>%ld</font>\n\n", now);
    
    // 当前时间
    tm_info = localtime(&now);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" 当前时间: <font color=#2ECC71>%s</font>\n", buffer);
    
    // 加一天(24小时 = 24*3600秒)
    time_t tomorrow = now + 24 * 3600;
    tm_info = localtime(&tomorrow);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" 明天此时: <font color=#3498DB>%s</font>\n", buffer);
    
    // 加一周(7天)
    time_t next_week = now + 7 * 24 * 3600;
    tm_info = localtime(&next_week);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf("下周此时: <font color=#9B59B6>%s</font>\n", buffer);
    
    // 减三天
    time_t three_days_ago = now - 3 * 24 * 3600;
    tm_info = localtime(&three_days_ago);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" 三天前: <font color=#E74C3C>%s</font>\n", buffer);
    
    // 加一个
    tm_info = localtime(&now);
    tm_info->tm_mon += 1;
    mktime(tm_info);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf("下月此时: <font color=#F39C12>%s</font>\n", buffer);
    
    // 加一年
    tm_info = localtime(&now);
    tm_info->tm_year += 1;
    mktime(tm_info);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    printf(" 明年此时: <font color=#E67E22>%s</font>\n", buffer);
}

int main() {
    time_add_subtract();
    return 0;
}

五、时区处理
5.1 获取当前时区信息

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

void get_timezone_info() {
    time_t now = time(NULL);
    struct tm *tm_info;
    char buffer[80];
    
    // <font color=#3498DB>获取本地时间(包含时区信息)</font>
    tm_info = localtime(&now);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", tm_info);
    printf(" 本地时间: <font color=#2ECC71>%s</font>\n", buffer);
    
    // <font color=#3498DB>获取时区偏移</font>
    strftime(buffer, sizeof(buffer), "%z", tm_info);
    printf(" 时区偏移: <font color=#E67E22>%s</font>\n", buffer);
    
    // <font color=#3498DB>获取时区名称</font>
    strftime(buffer, sizeof(buffer), "%Z", tm_info);
    printf(" 时区名称: <font color=#9B59B6>%s</font>\n", buffer);
}

int main() {
    get_timezone_info();
    return 0;
}

5.2 时区转换示例

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

void timezone_conversion() {
    time_t rawtime = time(NULL);
    struct tm *tm_info;
    char buffer[80];
    
    // <font color=#7F8C8D>保存原始时区</font>
    char *old_tz = getenv("TZ");
    printf(" 原始时间戳: <font color=#E67E22>%ld</font>\n\n", rawtime);
    
    // <font color=#E74C3C>设置为北京时间 (UTC+8)</font>
    setenv("TZ", "Asia/Shanghai", 1);
    tzset();
    tm_info = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", tm_info);
    printf("🇨🇳 北京时间: <font color=#2ECC71>%s</font>\n", buffer);
    
    // <font color=#E67E22>设置为东京时间 (UTC+9)</font>
    setenv("TZ", "Asia/Tokyo", 1);
    tzset();
    tm_info = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", tm_info);
    printf("🇯🇵 东京时间: <font color=#F39C12>%s</font>\n", buffer);
    
    // <font color=#3498DB>设置为纽约时间 (UTC-5/UTC-4)</font>
    setenv("TZ", "America/New_York", 1);
    tzset();
    tm_info = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", tm_info);
    printf("🇺🇸 纽约时间: <font color=#3498DB>%s</font>\n", buffer);
    
    // <font color=#9B59B6>设置为伦敦时间 (UTC+0/UTC+1)</font>
    setenv("TZ", "Europe/London", 1);
    tzset();
    tm_info = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", tm_info);
    printf("🇬🇧 伦敦时间: <font color=#9B59B6>%s</font>\n", buffer);
    
    // <font color=#7F8C8D>恢复原始时区</font>
    if (old_tz) {
        setenv("TZ", old_tz, 1);
    } else {
        unsetenv("TZ");
    }
    tzset();
}

int main() {
    timezone_conversion();
    return 0;
}

六、实用场景示例
6.1 计算程序运行时间

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

void measure_execution_time() {
    clock_t start, end;
    double cpu_time_used;
    
    start = clock();
    printf(" 程序开始运行...\n");
    
    // <font color=#F39C12>模拟耗时操作</font>
    for (int i = 0; i < 10000000; i++) {
        // 做一些计算
    }
    
    end = clock();
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    
    printf(" 程序结束\n");
    printf("  CPU执行时间: <font color=#E74C3C>%.3f</font> 秒\n", cpu_time_used);
}

int main() {
    measure_execution_time();
    return 0;
}

6.2 日志时间戳

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

void log_message(const char *level, const char *format, ...) {
    time_t now;
    struct tm *tm_info;
    char timestamp[30];
    char buffer[1024];
    
    // <font color=#3498DB>获取时间戳</font>
    time(&now);
    tm_info = localtime(&now);
    strftime(timestamp, 30, "%Y-%m-%d %H:%M:%S", tm_info);
    
    // <font color=#3498DB>格式化日志消息</font>
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    // <font color=#3498DB>根据日志级别设置颜色</font>
    char *level_color;
    switch(level[0]) {
        case 'I': level_color = "<font color=#2ECC71>"; break;  // INFO 绿色
        case 'W': level_color = "<font color=#F39C12>"; break;  // WARN 橙色
        case 'E': level_color = "<font color=#E74C3C>"; break;  // ERROR 红色
        default: level_color = "<font color=#3498DB>";
    }
    
    // <font color=#3498DB>输出日志</font>
    printf("<font color=#7F8C8D>[%s]</font> %s[%s]</font> %s\n", 
           timestamp, level_color, level, buffer);
}

int main() {
    log_message("INFO", "程序启动成功");
    log_message("INFO", "用户登录: %s", "张三");
    log_message("WARN", "磁盘空间不足,剩余: %d MB", 150);
    log_message("ERROR", "数据库连接失败: %s", "timeout");
    
    return 0;
}

6.3 计算年龄

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

int calculate_age(int birth_year, int birth_mon, int birth_day) {
    time_t now = time(NULL);
    struct tm *today = localtime(&now);
    
    int age = today->tm_year + 1900 - birth_year;
    
    // <font color=#3498DB>检查是否已经过了今年的生日</font>
    if (today->tm_mon + 1 < birth_mon || 
        (today->tm_mon + 1 == birth_mon && today->tm_mday < birth_day)) {
        age--;
    }
    
    return age;
}

int main() {
    int birth_year = 1990, birth_mon = 5, birth_day = 15;
    int age = calculate_age(birth_year, birth_mon, birth_day);
    
    printf(" 出生日期: <font color=#2ECC71>%d年%d月%d日</font>\n", 
           birth_year, birth_mon, birth_day);
    printf(" 当前年龄: <font color=#E74C3C>%d</font> 岁\n", age);
    
    return 0;
}

七、注意事项和最佳实践
7.1 2038年问题

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

void y2038_problem_demo() {
    // <font color=#F39C12>32位time_t的最大值</font>
    time_t max_32bit = 0x7FFFFFFF;  // 2147483647
    
    struct tm *tm_info = gmtime(&max_32bit);
    char buffer[30];
    strftime(buffer, 30, "%Y-%m-%d %H:%M:%S", tm_info);
    
    printf("  <font color=#E74C3C>32位时间戳最大值</font>: <font color=#E67E22>%ld</font>\n", max_32bit);
    printf(" 对应UTC时间: <font color=#F39C12>%s</font>\n", buffer);
    printf(" <font color=#E74C3C>1秒之后将溢出!</font>\n");
    
    // <font color=#3498DB>解决方案</font>
    printf("\n <font color=#2ECC71>解决方案:</font>\n");
    printf("   • 使用64位时间类型\n");
    printf("   • 升级到64位系统\n");
    printf("   • 使用其他时间表示法\n");
}

int main() {
    y2038_problem_demo();
    return 0;
}

7.2 线程安全处理

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

void thread_safety_demo() {
    time_t now = time(NULL);
    struct tm result;
    char buffer[30];
    
    // <font color=#E74C3C> 非线程安全</font>
    struct tm *unsafe = localtime(&now);
    printf("非线程安全: %s", asctime(unsafe));
    
    // <font color=#2ECC71>线程安全(localtime_r)</font>
    struct tm *safe = localtime_r(&now, &result);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", safe);
    printf(" 线程安全: <font color=#2ECC71>%s</font>\n", buffer);
}

int main() {
    thread_safety_demo();
    return 0;
}

7.3 常见陷阱

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

void common_pitfalls() {
    time_t now = time(NULL);
    struct tm tm_info;
    char buffer[30];
    
    printf("<font color=#E74C3C> 常见陷阱示例:</font>\n\n");
    
    // <font color=#F39C12>陷阱1:tm_mon从0开始</font>
    localtime_r(&now, &tm_info);
    printf("陷阱1: tm_mon = %d (实际月份应为 %d)\n", 
           tm_info.tm_mon, tm_info.tm_mon + 1);
    printf("        正确用法: tm_mon + 1\n\n");
    
    // <font color=#F39C12>陷阱2:tm_year从1900开始</font>
    printf("陷阱2: tm_year = %d (实际年份应为 %d)\n", 
           tm_info.tm_year, tm_info.tm_year + 1900);
    printf("        正确用法: tm_year + 1900\n\n");
    
    // <font color=#F39C12>陷阱3:时区影响</font>
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %Z", &tm_info);
    printf("陷阱3: 本地时间 = %s\n", buffer);
    printf("       注意时区对时间的影响\n");
}

int main() {
    common_pitfalls();
    return 0;
}
相关推荐
所谓伊人,在水一方3332 小时前
【机器学习精通】第2章 | 优化算法深度解析:从梯度下降到自适应优化器
人工智能·python·算法·机器学习·信息可视化
Storynone2 小时前
【Day24】LeetCode:122. 买卖股票的最佳时机 II,55. 跳跃游戏,45. 跳跃游戏II,1005. K次取反后最大化的数组和
python·算法·leetcode
悠哉悠哉愿意2 小时前
【单片机学习笔记】math库函数补充
c语言·笔记·单片机·学习
滴滴答滴答答2 小时前
机考刷题之 17&18&19&20&21&22 LeetCode 1248&121&43&93&62&63
算法·leetcode·职场和发展
炸膛坦客2 小时前
单片机/C语言八股:(五)32/64 位系统中,C/C++各变量类型所占字节数
c语言·开发语言·c++
fygfh.2 小时前
Linux的系统架构浅析
linux·arm开发·系统架构
for_ever_love__2 小时前
Objective-C学习 类别和扩展
学习·算法·objective-c
Sakinol#2 小时前
Leetcode Hot 100 ——回溯part02
算法·leetcode
无敌海苔咪2 小时前
【解决方案】CentOS 7 网络显示线缆已拔出
linux·运维·centos