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

如何用C++ date库解析秒与亚秒间无小数点的字符串?

问题

使用Howard Hinnant开发的date库时,遇到解析HH:mm:ssSSS格式时间字符串的问题:可以正常解析带分隔符的HH:mm:ss,SSS格式,但无法处理秒与亚秒之间无分隔符的HH:mm:ssSSS格式。不想通过修改字符串适配,询问是否可以通过date::parse()和std::numpunct实现解析。

附相关代码(已修正拼写及语法错误):

class PunctuationFacet
    : public std::numpunct<char>
{
public:
   PunctuationFacet(char numericPunctuation, size_t referenceCount = 0)
      : std::numpunct<char>(referenceCount)
      , _numericPunctuation(numericPunctuation) {}

protected:
    char do_decimal_point() const { return _numericPunctuation; }

private:
    char _numericPunctuation;
};

std::optional<uint64_t> parse(std::string_view value, char numericPunctuation)
{
    date::sys_time<std::chrono::milliseconds> timepoint;

    std::stringstream ss;
    ss.imbue(std::locale(ss.getloc(), new PunctuationFacet(numericPunctuation)));
    ss << value;
    ss >> date::parse("%H:%M:%S", timepoint);
    if (ss.fail()) [[unlikely]]
    {
        return std::nullopt;
    }
    return timepoint.time_since_epoch().count();
}

int main(int argumentCount, char **arguments)
{
    auto timestampDoesWork = parse("14:20:51,123", ',');
    auto timestampDoesNotWork = parse("14:20:51123", 0);
}
解决方案

仅通过std::numpunct无法实现HH:mm:ssSSS格式的解析,核心原因是:

  • std::numpunct的作用仅为指定小数点符号,但HH:mm:ssSSS中秒与毫秒之间没有任何分隔符,不存在可替换的小数点位置。date::parse的%S格式要求秒和亚秒部分必须有分隔符(小数点或numpunct指定的符号),否则会把51123整体当作秒数解析,超出合法范围导致失败。

要在不修改原字符串的前提下解析该格式,可以利用date库的格式化字符串扩展:

  1. 直接解析无分隔符格式:使用%H:%M:%S%3f格式字符串,其中%3f表示读取3位数字作为毫秒数,date::parse会自动拆分秒部分(如51)和后续3位(如123)。
    示例代码:

    std::optional<uint64_t> parse_no_sep(std::string_view value)
    {
        date::sys_time<std::chrono::milliseconds> timepoint;
        std::istringstream ss(std::string(value));
        if (!(ss >> date::parse("%H:%M:%S%3f", timepoint)))
            return std::nullopt;
        return timepoint.time_since_epoch().count();
    }
    

    调用parse_no_sep("14:20:51123")即可得到正确结果。

  2. 同时兼容两种格式:先尝试无分隔符格式,失败后再切换到带分隔符的解析逻辑:

    std::optional<uint64_t> parse_both(std::string_view value)
    {
        date::sys_time<std::chrono::milliseconds> timepoint;
        std::istringstream ss(std::string(value));
        
        // 先尝试无分隔符格式
        if (ss >> date::parse("%H:%M:%S%3f", timepoint))
            return timepoint.time_since_epoch().count();
        
        // 重置流,尝试带分隔符格式
        ss.clear();
        ss.seekg(0);
        ss.imbue(std::locale(ss.getloc(), new PunctuationFacet(',')));
        if (ss >> date::parse("%H:%M:%S", timepoint))
            return timepoint.time_since_epoch().count();
        
        return std::nullopt;
    }
    

    此函数可同时处理14:20:51,123和14:20:51123两种格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:15:35