C++如何解析无分隔符8位日期?std::get_time解析失败如何解决?
问题原因
代码本身没有错误,该问题是旧版MSVC标准库的std::get_time实现缺陷导致的。
MSVC 19.10(对应VS2017版本)的<iomanip>库中std::get_time的实现对无分隔符的连续日期格式支持存在bug,解析时无法正确识别连续拼接的数字格式串,会提前终止匹配导致解析失败。该问题在VS2019 16.0及以上版本的MSVC中已经修复,GCC、Clang的标准库实现也不存在该问题。
编译标记说明
目前没有可用的编译标记能修复旧版MSVC的该问题,缺陷存在于标准库的底层实现,无法通过编译开关调整。
替代解决方案
可以使用以下几种方案实现无分隔符日期解析需求:
- 方案1:使用MSVC提供的
_strptime_s安全函数,该函数是C标准strptime的MSVC实现,支持无分隔符的日期解析,示例代码如下:
#define _CRT_SECURE_NO_WARNINGS #include <cassert> #include <ctime> #include <cstring> #define MAKEDATE(d,m,y) (((y&0xFFFF)<<16)|((m&0xFF)<<8)|(d&0xFF)) uint32_t Get_Date(const char *str_date, const char **out, const char *format) { std::tm dt = {}; char *parse_end = _strptime(str_date, format, &dt); if (parse_end == nullptr) { if (out) *out = NULL; return MAKEDATE(1, 1, 1900); } else { if (out) *out = parse_end; return MAKEDATE(dt.tm_mday, 1 + dt.tm_mon, 1900 + dt.tm_year); } } int main(void) { assert(Get_Date("31122021", NULL, "%d%m%Y") == MAKEDATE(31, 12, 2021)); }
- 方案2:如果仅需要处理固定长度的8位无分隔符日期,可以手动拆分字符串转换,兼容性最强,没有平台依赖:
#include <cassert> #include <cstdint> #include <cstring> #include <cstdlib> #define MAKEDATE(d,m,y) (((y&0xFFFF)<<16)|((m&0xFF)<<8)|(d&0xFF)) uint32_t Get_Date(const char *str_date, const char **out, const char *format) { // 仅处理%d%m%Y格式的8位日期场景,其他格式可自行扩展 if (strlen(str_date) < 8) { if (out) *out = NULL; return MAKEDATE(1, 1, 1900); } char day_buf[3] = {str_date[0], str_date[1], '\0'}; char month_buf[3] = {str_date[2], str_date[3], '\0'}; char year_buf[5] = {str_date[4], str_date[5], str_date[6], str_date[7], '\0'}; int d = atoi(day_buf); int m = atoi(month_buf); int y = atoi(year_buf); if (out) *out = str_date + 8; return MAKEDATE(d, m, y); } int main(void) { assert(Get_Date("31122021", NULL, "%d%m%Y") == MAKEDATE(31, 12, 2021)); }
- 方案3:如果项目允许引入第三方库,可以使用Howard Hinnant的date库,该库是C++20标准日历库的原型实现,跨平台且日期解析功能完善,支持任意格式的日期解析。
内容的提问来源于stack exchange,提问作者Moige
相关产品推荐
相关产品推荐

