DateTime::ToString 日期时间文本格式化深度解析(C++)

发布于:2025-07-30 ⋅ 阅读:(23) ⋅ 点赞:(0)

⚙️ DateTime::ToString 日期时间文本格式化深度解析(C++)

——结构、流程、原理与完整实现

引用

  1. ppp/DateTime.cpp#L139
  2. 家山别矣 想念天涯子 怅然老矣 我共二三子 惶然梦矣 梦也徘徊起
  3. 暮暮朝朝 老去吟游 离魂无据 梦里痴痴语
🏗️ 一、整体结构
DateTime
-int year
-int month
-int day
-int hour
-int minute
-int second
-int millisecond
-int64_t microseconds
-int64_t total_hours
+ToString(const char* format, bool fixed) : noexcept
#PaddingLeft()

组成模块

  1. 格式解析器:扫描格式字符串,识别yMdHmsfuT格式符
  2. 状态追踪器:使用symbolsymbol_size跟踪当前格式组
  3. 组件处理器:将时间分量转换为字符串
  4. 宽度控制器:实现fixed模式下的截断/补零
  5. 字符串构建器:拼接最终结果

🔄 二、处理流程
非空
相同
不同
循环
循环
开始
format
非空?
返回空字符串
初始化状态
遍历格式字符串
读取字符ch
是否格式符?
与当前
symbol相同?
增加symbol_size
处理当前组
设置新symbol
ProcessGroup
添加字面字符
结束?
返回结果
⏱️ 三、格式处理原理

关键算法

while (*format) {
    ch = *format++;
    if (是格式符(ch)) {
        if (symbol != 0 && symbol != ch) {
            symbol_exec(0); // 提交当前组
        }
        symbol = ch;        // 设置新符号
        symbol_size++;      // 增加计数
    } else {
        symbol_exec(ch);    // 提交组并添加字面值
    }
}
symbol_exec(0); // 处理剩余组

符号处理器行为

00 00 01 01 02 02 03 03 04 获取分量值 fixed宽度调整 添加字面字符 重置状态 处理流程 symbol_exec处理流程

🛠️ 四、完整代码实现
ppp::string DateTime::ToString(const char* format, bool fixed) noexcept {
    ppp::string result;
    if (NULL == format || *format == '\x0') {
        return result;
    }

    char symbol = 0;
    int symbol_size = 0;
    
    auto symbol_exec = int ch noexcept {
        ppp::string seg;
        switch (symbol) {
            case 'y': seg = stl::to_string<ppp::string>(Year()); break;
            case 'M': seg = stl::to_string<ppp::string>(Month()); break;
            case 'd': seg = stl::to_string<ppp::string>(Day()); break;
            case 'H': seg = stl::to_string<ppp::string>(Hour()); break;
            case 'm': seg = stl::to_string<ppp::string>(Minute()); break;
            case 's': seg = stl::to_string<ppp::string>(Second()); break;
            case 'f': seg = stl::to_string<ppp::string>(Millisecond()); break;
            case 'u': seg = stl::to_string<ppp::string>(Microseconds()); break;
            case 'T': seg = stl::to_string<ppp::string>((int64_t)TotalHours()); break;
        }

        if (fixed && symbol != 0) {
            int64_t seg_size = seg.size();
            if (seg_size > symbol_size) {
                seg = seg.substr(seg_size - symbol_size);
            } 
            else if (seg_size < symbol_size) {
                seg = PaddingLeft(seg, symbol_size, '0');
            }
        }

        if (ch != 0) {
            seg.append(1, ch);
        }

        result += seg;
        symbol = 0;
        symbol_size = 0;
    };

    const char* p = format;
    while (*p) {
        char ch = *p++;
        if (ch == 'y' || ch == 'M' || ch == 'd' || 
            ch == 'H' || ch == 'm' || ch == 's' || 
            ch == 'f' || ch == 'u' || ch == 'T') 
        {
            if (symbol != 0 && symbol != ch) {
                symbol_exec(0);
            }
            symbol = ch;
            symbol_size++;
        } else {
            symbol_exec(ch);
        }
    }
    symbol_exec(0);
    
    return result;
}

template <typename _Ty>
_Ty DateTime::PaddingLeft(const _Ty& s, int count, char padding_char) noexcept {
    int string_length = static_cast<int>(s.size());
    if (count < 1 || count <= string_length) {
        return s;
    }

    _Ty r = s;
    for (int i = 0; i < count - string_length; i++) {
        r = _Ty(1ul, padding_char) + r;
    }
    return r;
}

🔍 五、核心机制剖析
1. 格式符处理矩阵
输入 当前状态 动作
新符号 symbol相同 symbol_size++
新符号 symbol不同 提交旧组,开始新组
非符号 有状态 提交组,添加字面值
非符号 无状态 直接添加字面值
2. fixed模式控制逻辑
直接输出
seg.size > symbol_size
seg.size < symbol_size
CheckLength
过长
截断方向
低位
过短
填充方向
左侧
填充字符
'0'
相等
3. 时间分量映射关系
y
年份
M
月份
d
日期
H
小时
m
分钟
s
秒钟
f
毫秒
u
微秒
T
总小时数

💡 六、应用场景示例

1. 标准日期格式

// 输出:2025-07-29
ToString("yyyy-MM-dd", true)

处理流程

格式解析器 状态追踪 结果生成 "yyyy" → symbol='y', size=4 '-' → 非符号 提交组 → "2025" 添加"-" "MM" → symbol='M', size=2 '-' → 非符号 提交组 → "07"(补齐) 添加"-" "dd" → symbol='d', size=2 提交组 → "29" 格式解析器 状态追踪 结果生成

2. 精确时间戳

// 输出:23:38:03.000000
ToString("HH:mm:ss.ffffff", false)

3. 压缩日期格式

// 输出:25/7/29
ToString("yy/M/d", true)

📌 总结要点

  1. 状态驱动设计:双变量(symbol/size)实现高效状态跟踪
  2. 分层处理架构
    • 格式扫描 → 状态管理 → 分量转换 → 宽度控制 → 结果构建
  3. 关键处理流程
  4. 流程子图
1
格式解析
格式解析
1
识别格式符 (5%)
识别格式符 (5%)
分量获取
分量获取
1
调用成员函数 (5%)
调用成员函数 (5%)
字符串处理
字符串处理
1
fixed模式调整 (4%)
fixed模式调整 (4%)
结果构建
结果构建
1
拼接最终字符串 (4%)
拼接最终字符串 (4%)
数据转换流程
  1. 核心算法

    • 线性扫描格式字符串 O(n)
    • 状态变更触发分组处理
    • 数值到字符串的精确转换
  2. 流程子图

格式符
非格式符
过长
过短
相等
开始解析
扫描格式字符串
是否与当前
符号相同
增加计数器
提交当前组
处理字符
获取时间分量
转字符串
fixed模式?
调整宽度
加入结果
截断末尾
左侧补零
添加为字面字符
继续扫描
是否结束
提交末组
返回结果

“日期格式化是时间数据的符号化表达——状态机驱动字符串的精密重组”


网站公告

今日签到

点亮在社区的每一天
去签到