能省空间但仅限特定场景;需33位,可用uint64_t压缩年月日时分秒,但牺牲可读性、类型安全与时区支持,普通业务不推荐。

位运算存日期时间,真能省空间吗?
能,但只在特定场景下值得做——比如嵌入式设备里要塞几百个带时间戳的传感器记录,或者高频交易系统里每纳秒都要争抢内存带宽。普通业务代码里用 struct tm 或 std::chrono::system_clock::time_point 更安全、可读性更好。位压缩本质是用可读性和类型安全换几个字节,别为了“炫技”硬上。
怎么把年月日时分秒塞进一个 uint64_t
先算清楚最小位宽需求:
– 年份(2000–2099):100种可能 → 至少 7 位(2⁷=128)
– 月份(1–12):12种 → 4 位
– 日(1–31):31种 → 5 位
– 小时(0–23):24种 → 5 位
– 分钟(0–59):60种 → 6 位
– 秒(0–59):60种 → 6 位
加起来共 33 位,uint32_t 够用,但留点余量推荐 uint64_t。
典型布局(低位到高位):
– [0–5] 秒
– [6–11] 分钟
– [12–16] 小时
– [17–21] 日
– [22–25] 月
– [26–32] 年(以2000为基,存0–99)
提取示例:
uint64_t packed = ...; int sec = (packed & 0x3F) >> 0; // 0x3F = 6位全1 int min = (packed & 0xFC0) >> 6; // 0xFC0 = 6位左移6位 int hour = (packed & 0x1F000) >> 12; // 5位,掩码0x1F > 17; // 5位,掩码0x1F > 22; // 4位,掩码0xF > 26; // 7位,掩码0x7F <h3>写入时最容易踩的坑</h3><p>位移和掩码顺序错、溢出没检查、跨平台字节序误判(其实位域不涉字节序,但若用指针强转就危险)、忘记闰年/大小月校验——这些都得在打包前做。</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)"><img src="https://img.php.cn/upload/manual/000/000/001/5d6de31fedca2993.png" alt="C函数速查手册(CHM版)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)" class="overflowclass">C函数速查手册(CHM版)</a> <p class="overflowclass">C函数速查手册(CHM版)</p> </div> <a rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>
-
别直接用用户输入塞进去:比如传入 month=13,右移后仍会写进那4位,但解包时得到非法值;必须先校验
month >= 1 && month -
年份偏移要统一:存
year - 2000还是year - 1970?解包时必须严格对应,否则 2025 可能变成 1997 -
避免用位域 struct 混淆:像
struct { uint64_t sec:6; uint64_t min:6; ... }看似方便,但 C++ 标准不保证内存布局跨编译器一致,且无法直接 memcpy 到网络或文件——老老实实用掩码+移位更可控
性能真比 struct tm 快?
单次读写几乎没差别,现代 CPU 对简单位运算和结构体字段访问的耗时都在 1–2 个周期内。真正影响性能的是后续操作:比如你要对 10 万个时间做“是否同一天”判断,位存储可以 (a >> 17) == (b >> 17) 一次移位搞定;而 tm 得先 mktime 转成 time_t 再除以 86400 —— 这里才拉开差距。
但注意:
– 所有算术(如加减分钟)必须手动处理进位,代码易错
– 无法直接用 strftime、localtime 等标准函数
– 调试时看十六进制数不如看 {.tm_year=125, .tm_mon=4, ...} 直观
所以除非你明确卡在内存带宽或 cache line 数量上,否则别动它。
最常被忽略的一点:时区。位压缩里存的全是本地时间裸值,没有时区标识。如果数据要跨时区解析,或者要和 UTC 时间对齐,这套方案立刻崩掉——这时候宁可多占 8 字节存一个 int8_t timezone_offset_minutes。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










