使用C语言编写windows特有的_mktime64和_localtime64_s

文章提供了一个修复后的_mktime64函数,该函数考虑了时区计算,使得其输出结果与Windows系统的_mktime64函数一致。同时,还包括了一个_int64_to_localtime64_s函数,将int64时间戳转换为日期时间结构。这两个函数对于跨平台的日期时间处理具有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上看到有编写_mktime64的帖子,但是他们写的_mktime64输出的结果与Windows的输出结果不一致。经过本人对windows的_mktime64函数实现的跟踪研究,发现网上最接近正确答案的写法缺少对时区的计算。

一、_mktime64 日期时间转int64

/*
 *相比网上其它帖子的源码进行完善,输出结果与windows自带的_mktime64输出结果一致
 *_tm为当前真实日期,此处与windows的入参有所不同
 */
_int64 _mktime64(const tm& _tm)
{
    tm _tmp = _tm;
    if (0 >= (int) (_tmp.tm_mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
         _tmp.tm_mon += 12;      /* Puts Feb last since it has leap day */
         _tmp.tm_year -= 1;
    }

    return  ((((_tmp.tm_year/4 - _tmp.tm_year/100 + _tmp.tm_year/400 + 367*_tmp.tm_mon/12 + _tmp.tm_mday) +
                        _tmp.tm_year*365 - 719499
                    )*24 + _tmp.tm_hour /* now have hours */
                )*60 + _tmp.tm_min /* now have minutes */
            )*60 + _tmp.tm_sec /* finally seconds */
            - 8*3600; /*时区*/
};

二、_localtime64_s int64转日期时间

void _localtime64_s(const long long& _iTime, tm& _tm)
{
    #define CHCK_IS_LEAP_YEAR(y)  (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
    int startYear = 1970;
    long long _iTimep = _iTime;
    _iTimep += 8*3600;

    _tm.tm_sec = _iTimep % 60;
    _tm.tm_min = ((_iTimep - _tm.tm_sec) / 60) % 60;
    _tm.tm_hour  = (((_iTimep - _tm.tm_sec) / 60 - _tm.tm_min) / 60) % 24;

    int _alldays = (((_iTimep - _tm.tm_sec) / 60 - _tm.tm_min) / 60 - _tm.tm_hour) / 24;

    _tm.tm_wday = _alldays % 6 + 1;
    _tm.tm_isdst = 0;
    _tm.tm_year = _alldays / 365 + startYear; /*简易算法,直接用365整除,目前满足计算结果*/

    int _ndays = 0; /*计算从startYear到_tm.tm_year-1年总计天数*/
    for(int i = startYear; i < _tm.tm_year; i++)
    {
        if(CHCK_IS_LEAP_YEAR(i)){
            _ndays += 366;
        }else{
            _ndays += 365;
        }
    }

    int k,leap;
    int yearday = _alldays - _ndays;
    _tm.tm_yday = yearday;
    int _months_days[2][13] =
    {
        {0,31,28,31,30,31,30,31,31,30,31,30,31},
        {0,31,29,31,30,31,30,31,31,30,31,30,31}
    };

    if(CHCK_IS_LEAP_YEAR(_tm.tm_year)){
        leap = 1;
    }else{
        leap = 0;
    }

    for(k = 1; yearday > _months_days[leap][k]; k++)
        yearday -= _months_days[leap][k];
    _tm.tm_mon = k;
    _tm.tm_mday = yearday + 1;
};
### 解决 `_mktime64` 找不到标识符的问题 #### 问题分析 在使用 Microsoft Visual Studio 编译程序时,如果遇到错误 `error C3861: "_mktime64": 找不到标识符`,通常是由于以下几个原因之一引起的: - 缺少必要的头文件包含。 - 使用的编译器版本不再支持 `_mktime64` 函数。 - 配置中未正确指定所需的库文件。 虽然提到的时间戳转换问题涉及 PHP 的 `date.timezone` 设置[^1],但这与 C++ 中 `_mktime64` 的使用并无直接关联。此处重点在于解决 C++ 编译环境中 `_mktime64` 的不可用性。 --- ### 解决方案 #### 方法一:确认是否启用了正确的头文件 确保在代码中包含了适当的时间处理头文件。对于 `_mktime64` 函数,需包含如下头文件: ```cpp #include <ctime> // C++ 标准库头文件 // 或者 #include <time.h> // C 标准库头文件 ``` 注意:`_mktime64` 是微软特定的扩展函数,用于处理 64 位时间戳。它并不是 C/C++ 标准的一部分,因此仅在 Windows 平台上可用。 --- #### 方法二:检查编译器版本兼容性 从 Visual Studio 2015 (VS2015) 开始,微软逐步弃用了某些旧版 API,转而推荐更现代化的替代品。如果你使用的编译器版本较新(如 VS2019 或更高),可能需要替换 `_mktime64` 为其他等效函数。 ##### 替代方案 可以改用标准库中的 `std::tm` 结合 `std::mktime` 来完成相同的功能。例如: ```cpp #include <iostream> #include <ctime> int main() { std::tm time_info = {}; time_info.tm_year = 2023 - 1900; // 年份相对于 1900 的偏移量 time_info.tm_mon = 9; // 月份从 0 开始计数 time_info.tm_mday = 1; // 日 time_t result = mktime(&time_info); // 将 tm 转换为秒级时间戳 if (result != -1) { std::cout << "Time since epoch: " << result << " seconds\n"; } else { std::cerr << "Error converting time.\n"; } return 0; } ``` --- #### 方法三:添加必要的库链接 即使包含了正确的头文件,仍可能出现链接阶段的错误。这是因为 `_mktime64` 可能依赖于特定的运行时库。为此,可以在项目设置中显式链接相关库。 ##### 设置步骤 1. **进入项目属性页面** - 在 Visual Studio 中右键点击项目名称,选择“属性”。 2. **配置附加依赖项** - 导航至 **Linker -> Input -> Additional Dependencies**。 - 添加 `libcmt.lib` 或 `msvcrt.lib`,具体取决于你的运行时模式(静态/动态链接)。 --- #### 方法四:回退到较低版本的编译器 如果确实需要使用 `_mktime64` 且无法迁移到现代接口,则可以选择降级到早期版本的 Visual Studio(如 VS2010)。不过这种方法并不推荐,因为它会带来安全性性能上的隐患。 --- ### 示例代码修正 以下是修复后的代码示例,展示了如何正确使用 `_mktime64`: ```cpp #include <iostream> #include <ctime> int main() { std::tm time_info = {}; time_info.tm_year = 2023 - 1900; // 年份相对于 1900 的偏移量 time_info.tm_mon = 9; // 月份从 0 开始计数 time_info.tm_mday = 1; // 日 #ifdef _WIN32 __time64_t result = _mktime64(&time_info); // 使用 _mktime64 处理 64 位时间戳 #else time_t result = mktime(&time_info); // 其他平台使用标准库函数 #endif if (result != -1) { std::cout << "Time since epoch: " << result << " seconds\n"; } else { std::cerr << "Error converting time.\n"; } return 0; } ``` --- ### 总结 通过上述方法之一即可解决 `_mktime64` 找不到标识符的问题。推荐优先尝试方法一方法二,因为它们不需要更改现有开发环境;只有当条件不允许时才考虑调整编译器或运行时库。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值