C++中ISO 8601格式时间戳字符串的严格校验问题
校验ISO 8601时间戳合法性的解决方案
由于Boost和标准库chrono组件会自动调整非法时间值而非抛出错误,要实现严格校验需分两步:格式结构校验和数值合法性校验,以下是基于C++标准库的实现方案:
步骤1:格式匹配(正则表达式)
先用正则表达式匹配ISO 8601的核心格式(覆盖基本格式和扩展格式),确保时间戳的结构符合标准,避免混合分隔符等非法情况。
示例正则表达式:
const std::regex iso8601_regex( R"(^(\d{4})(-?)(\d{2})\2(\d{2})T(\d{2})(:?)(\d{2})\6(\d{2})(\.\d+)?$)" );
该正则会强制分隔符(-和:)要么全有要么全无,同时匹配可选的小数秒部分。
步骤2:提取字段并做数值校验
格式匹配通过后,提取年、月、日、时、分、秒等字段,逐一校验数值范围:
核心校验规则
- 月份:必须在1-12之间
- 日期:根据月份和闰年判断合法天数(如2月平年28天、闰年29天;4/6/9/11月30天,其余月份31天)
- 小时:0-23
- 分钟:0-59
- 秒:0-59(若需支持闰秒可放宽至0-60)
- 年份:可根据业务需求添加范围限制(如1970-2100)
完整代码示例
#include <iostream> #include <string> #include <regex> #include <stdexcept> // 判断闰年 bool is_leap_year(int year) { if (year % 4 != 0) return false; if (year % 100 != 0) return true; return year % 400 == 0; } // 获取对应月份的最大天数 int get_max_day(int year, int month) { switch (month) { case 2: return is_leap_year(year) ? 29 : 28; case 4: case 6: case 9: case 11: return 30; default: return 31; } } // 校验ISO 8601时间戳合法性 bool validate_iso8601(const std::string& timestamp) { std::smatch match; const std::regex iso8601_regex( R"(^(\d{4})(-?)(\d{2})\2(\d{2})T(\d{2})(:?)(\d{2})\6(\d{2})(\.\d+)?$)" ); // 格式匹配校验 if (!std::regex_match(timestamp, match, iso8601_regex)) { return false; } // 提取字段并转为整数 int year = std::stoi(match[1]); int month = std::stoi(match[3]); int day = std::stoi(match[4]); int hour = std::stoi(match[5]); int minute = std::stoi(match[7]); int second = std::stoi(match[8]); // 数值合法性校验 if (month < 1 || month > 12) return false; if (day < 1 || day > get_max_day(year, month)) return false; if (hour < 0 || hour > 23) return false; if (minute < 0 || minute > 59) return false; if (second < 0 || second > 59) return false; // 支持闰秒可改为second <= 60 return true; } int main() { // 测试用例 std::string valid1 = "20021012T235920218"; // 合法基本格式 std::string valid2 = "2002-10-12T23:59:20.218"; // 合法扩展格式 std::string invalid_hour = "20021012T255920218"; // 小时溢出 std::string invalid_date = "2014-02-30T21:35:34"; // 2月30日 std::cout << valid1 << ": " << (validate_iso8601(valid1) ? "合法" : "非法") << std::endl; std::cout << valid2 << ": " << (validate_iso8601(valid2) ? "合法" : "非法") << std::endl; std::cout << invalid_hour << ": " << (validate_iso8601(invalid_hour) ? "合法" : "非法") << std::endl; std::cout << invalid_date << ": " << (validate_iso8601(invalid_date) ? "合法" : "非法") << std::endl; return 0; }
代码说明
- 正则表达式确保时间戳结构严格符合ISO 8601规范,拒绝混合分隔符等非法格式;
- 数值校验通过手动判断月份天数、闰年等规则,直接拒绝所有溢出的时间值;
- 若业务需支持更多ISO 8601变体(如带时区、仅日期/时间部分),可扩展正则和校验逻辑。
内容的提问来源于stack exchange,提问作者katarzyna
相关产品推荐
相关产品推荐

