You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CET时区下mktime()函数异常:tm_isdst=1时时间转换疑问

为什么CET时区下设置tm.tm_isdst=1时,mktime会把2019-03-31 02:00转为01:00?

这个现象其实和CET时区的夏令时切换规则,以及mktime()的核心行为逻辑直接相关,咱们一步步拆解:

首先明确夏令时切换的时间点

CET时区(中欧标准时间)在2019年3月31日当地时间02:00会直接跳转到03:00——也就是说,这一天根本不存在02:00到03:00之间的时间区间,时钟直接拨快1小时进入夏令时(CEST,UTC+2)。

再看mktime()的关键特性

mktime()的核心作用是把struct tm格式的时间转换为Unix时间戳,但它还有一个重要功能:规范化输入的时间参数。如果传入的struct tm描述的是一个不存在的无效时间(比如刚才说的缺失的02:00区间),它会自动调整到最近的有效时间,同时更新传入的struct tm结构体的所有字段(包括tm_isdst、tm_zone等)。

结合你的测试结果分析

咱们对着你的测试代码和输出逐一拆解:

1. 设置tm.tm_isdst=0的情况

你告诉mktime():这个时间是标准时间(CET,UTC+1)。但2019-03-31 02:01的CET时间已经过了夏令时切换点,实际此时当地时间已经是CEST(UTC+2)的03:01了。所以mktime()会自动把时间调整为有效的CEST 03:01,同时把tm_isdst更新为1(表示处于夏令时),对应的时间戳1553994060就是UTC时间2019-03-31 01:01:00(加上CEST的2小时正好是03:01)。

2. 设置tm.tm_isdst=1的情况

你指定这个时间是夏令时(CEST,UTC+2),但CEST的02:01是完全不存在的——因为切换后,当地时间从CET的02:00直接跳到CEST的03:00,CEST的02:01对应的UTC时间是00:01,但此时当地时间还处于CET的01:01(UTC 00:01 +1小时)。所以mktime()会把这个无效的时间调整为有效的CET 01:01,同时把tm_isdst更新为0(表示处于标准时间),时间戳1553990460就是UTC时间2019-03-31 00:01:00。

3. 设置tm.tm_isdst=-1的情况

这是让mktime()自动判断是否处于夏令时,它会正确识别此时已经完成夏令时切换,所以直接调整为有效的CEST 03:01,和第一种情况的结果一致。

总结

你觉得这是“无效参数组合”没错,但mktime()的设计就是要处理这类无效输入——它会将传入的struct tm视为一个“日历时间的近似值”,自动修正到最近的有效时间,同时更新结构体的字段来匹配最终的有效时间。这是符合POSIX标准的预期行为。


你的测试代码

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
void reset(struct tm* tm){ 
    (*tm) = (const struct tm){0}; 
    tm->tm_sec = 0; 
    tm->tm_min = 1; 
    tm->tm_hour = 2; 
    tm->tm_mon = 2; 
    tm->tm_mday = 31; 
    tm->tm_year = 2019 - 1900; 
} 
int main(int argc, char **argv) { 
    struct tm tm; 
    int secs; 
    reset(&tm); 
    printf("mktime调用前\n"); 
    printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); 
    tm.tm_isdst = 0; 
    secs = mktime(&tm); 
    printf("设置tm.tm_isdst = 0调用mktime后;\n"); 
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs); 
    reset(&tm); 
    tm.tm_isdst = 1; 
    secs = mktime(&tm); 
    printf("设置tm.tm_isdst = 1调用mktime后;\n"); 
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs); 
    reset(&tm); 
    tm.tm_isdst = -1; 
    secs = mktime(&tm); 
    printf("设置tm.tm_isdst = -1调用mktime后\n"); 
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs); 
    return 0; 
}

运行输出

% date命令输出:Sun Mar 31 06:50:42 CEST 2019
% test_mktime
mktime调用前
2019-03-31 02:01:00
设置tm.tm_isdst = 0调用mktime后;
2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060
设置tm.tm_isdst = 1调用mktime后;
2019-03-31 01:01:00 TZ=CET , tm_isdst = 0, timestamp=1553990460
设置tm.tm_isdst = -1调用mktime后
2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060

内容的提问来源于stack exchange,提问作者Songe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:10:16