C++make12 make24小时制转换

2026-03-23 08:30:43 735阅读

C++ 实现 12 小时制与 24 小时制时间格式双向转换

在日常开发中,时间格式的解析与转换是基础而高频的需求。尤其在国际化应用、日志分析、用户界面展示等场景下,12 小时制(如 02:30 PM)与 24 小时制(如 14:30)之间的准确互转至关重要。C++ 标准库虽提供 <chrono><iomanip> 等强大工具,但对带 AM/PM 的字符串解析仍需手动处理。本文将完整实现一个健壮、可复用的 C++ 时间转换模块,支持双向转换、输入校验与异常防护,代码简洁清晰,符合现代 C++ 风格(C++17 及以上)。

核心设计思路

转换逻辑需覆盖三类关键问题:

  • 语义映射12:00 AM00:0012:00 PM12:0001:00 PM13:00
  • 格式鲁棒性:兼容空格、大小写(am/AM/a.m.)、前导零缺失(9:5 AM);
  • 错误防御:拒绝非法输入(如 13:00 AM25:008:65 PM),返回明确错误状态。

我们不依赖第三方库,仅使用 <string><cctype><sstream><stdexcept>,确保轻量可嵌入。

完整实现代码

以下为封装在命名空间 timeconv 中的两个核心函数

#include <string>
#include <cctype>
#include <sstream>
#include <stdexcept>

namespace timeconv {

// 将 12 小时制字符串(如 "02:30 PM")转为 24 小时制 "HH:MM" 格式
std::string to_24h(const std::string& input) {
    if (input.empty()) {
        throw std::invalid_argument("Empty input string");
    }

    // 提取时间主体与周期标识(AM/PM)
    std::string time_part, period;
    size_t pos = input.find_first_of("aApPmM");
    if (pos == std::string::npos) {
        throw std::invalid_argument("Missing AM/PM indicator");
    }

    // 分离时间数字部分与周期部分(忽略中间空格)
    time_part = input.substr(0, pos);
    period = input.substr(pos);

    // 清理 period:只保留字母并转大写
    std::string clean_period;
    for (char c : period) {
        if (std::isalpha(c)) {
            clean_period += std::toupper(c);
        }
    }
    if (clean_period != "AM" && clean_period != "PM") {
        throw std::invalid_argument("Invalid period: " + clean_period);
    }

    // 解析 HH:MM
    std::istringstream iss(time_part);
    int hour = 0, minute = 0;
    char colon;
    if (!(iss >> hour >> colon >> minute) || colon != ':') {
        throw std::invalid_argument("Invalid time format: missing colon or digits");
    }

    // 校验数值范围
    if (hour < 1 || hour > 12) {
        throw std::invalid_argument("Hour must be 1–12 in 12-hour format");
    }
    if (minute < 0 || minute > 59) {
        throw std::invalid_argument("Minute must be 0–59");
    }

    // 转换逻辑
    if (clean_period == "AM") {
        if (hour == 12) hour = 0;  // 12:xx AM → 00:xx
    } else {  // PM
        if (hour != 12) hour += 12;  // 1:xx PM → 13:xx, ..., 11:xx PM → 23:xx
        // 12:xx PM remains 12:xx
    }

    // 格式化为两位数字符串
    std::ostringstream oss;
    oss.fill('0');
    oss.width(2);
    oss << hour;
    oss << ':';
    oss.width(2);
    oss << minute;
    return oss.str();
}

// 将 24 小时制字符串(如 "14:30")转为 12 小时制 "H:MM AM/PM"(无前导零)
std::string to_12h(const std::string& input) {
    if (input.empty()) {
        throw std::invalid_argument("Empty input string");
    }

    std::istringstream iss(input);
    int hour = 0, minute = 0;
    char colon;
    if (!(iss >> hour >> colon >> minute) || colon != ':') {
        throw std::invalid_argument("Invalid 24-hour format: expected HH:MM");
    }

    if (hour < 0 || hour > 23) {
        throw std::invalid_argument("Hour must be 0–23 in 24-hour format");
    }
    if (minute < 0 || minute > 59) {
        throw std::invalid_argument("Minute must be 0–59");
    }

    std::string period = (hour < 12) ? "AM" : "PM";
    int display_hour = hour % 12;
    if (display_hour == 0) display_hour = 12;  // 0→12, 12→12, 13→1...

    std::ostringstream oss;
    oss << display_hour << ':';
    oss.fill('0');
    oss.width(2);
    oss << minute;
    oss << ' ' << period;
    return oss.str();
}

} // namespace timeconv

使用示例与测试验证

调用方式直观简洁:

#include <iostream>
#include <string>

int main() {
    try {
        std::cout << timeconv::to_24h("12:00 AM") << '\n';  // "00:00"
        std::cout << timeconv::to_24h("01:45 PM") << '\n';  // "13:45"
        std::cout << timeconv::to_24h("9:05 am") << '\n';   // "09:05"
        std::cout << timeconv::to_24h("12:30 PM") << '\n';  // "12:30"

        std::cout << timeconv::to_12h("00:15") << '\n';     // "12:15 AM"
        std::cout << timeconv::to_12h("12:00") << '\n';     // "12:00 PM"
        std::cout << timeconv::to_12h("23:59") << '\n';     // "11:59 PM"

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << '\n';
    }
    return 0;
}

运行结果严格符合标准时间语义,且所有边界情况(如 12:00 AM/PM、单数字小时、大小写混用)均被正确处理。

注意事项与扩展建议

  • 当前实现默认采用宽松空格处理,若需更严格的格式匹配(如禁止 9:5 AM),可在解析前添加正则或增强分词逻辑;
  • 对于高并发服务,可将字符串操作改为 std::string_view(C++17)以减少拷贝
  • 若需支持时区或秒级精度,建议在此基础上集成 <chrono> 进行时间点运算;
  • 生产环境建议增加单元测试覆盖全部边界用例(如 00:0012:60、空输入、纯空格等)。

结语

本文提供的 C++ 时间转换模块兼具正确性、可读性与工程实用性。它不依赖外部组件,逻辑清晰,错误提示明确,可直接集成至各类 C++ 项目中。掌握此类基础转换能力,不仅提升日常编码效率,也为构建更复杂的时间处理系统奠定坚实基础。时间虽无形,但其表达必须精确——这正是程序员对确定性的不懈追求。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

目录[+]