pre
重构模块,一个过期时间的功能点,想要实现更灵活的配置,支持:
- 时间长度过期:after 3600s (3600秒之后过期)
- 时间点过期: appoint 2023-10-09 05:00:00 (localtime 过期)
- 以天为单位的时刻过期:point 04:00:00 (每天4点过期)
- 当天4点前获得道具,当天4点过期
- 当天4点后获得道具,第二天4点过期
旧的样子
之前老的时间模块有这些函数:
- get_current_timestamp - 获取当前时间戳
- get_timestamp_from_string - 获取指定时间戳的format string
- get_string_from_timestamp - 获取指定format string 对应的时间戳
- get_day_start_timestamp - 获得当天开始的时间戳(localtime 0点)
期望的样子
看起来好像是够用的,组合一下,基本可以实现上面的需求;不过可能是这个模块本身写的比较乱(命名不是像上面整齐、函数实现有用c的,有用std::chrono的、ms/s用了两个函数,而且命名看不出取到的是什么、数据类型有int32,int64,uint64,time_t)就打算重新整理一下,期望:
- timestamp 相关的函数用模版区分 seconds/millisecs
- format string 提供只提供一种方式(基本都是内部使用,不涉及utc/http不同格式的format)
- from string 也就只从一种格式解析,但是期望同时能解析只有date,只有time的情况(覆盖上面的第三种配置方式)
- 性能上 format string 同一秒不做重复解析,需要缓存上次解析后的字符串,对日志这种经常获取当前时间字符串的场景可以提升不少性能
- 因为主要用在游戏开发上,精度到millisecs基本够用
- 基于std::chrono,之后升级到c++20可以更灵活的替换部分函数
实现
实现上其实没太复杂,只有 from string 的处理上需要覆盖期望没有用 std::get_time/strptime,自己写了解析,代码长了点,实测性能比 std::get_time 高1倍
code: https://github.com/kinly/anything/blob/main/easy_datetime.h
后
之前有印象google的时间解析库比 std::get_time 快10倍还是20倍的样子,想着有什么办法能给自己写的提高点性能,尝试无果后找隔壁桌的大佬帮忙。
- 首先他觉得这样的东西应该在逻辑层处理,作为datetime模块基本只需要 旧的样子 就好(我觉得日常场景挺频繁的,基础模块做好这些没关系,毕竟已经写好了….)
- format string 用 ms 级别缓存,后来看他写的也是用 s 的,但是可能因为他的精度是macro second 记混了,明确下:一般场景用 ms 反而会拖累性能,用 s 更合适
- datetime 模块需要缓存 loacltime,不然做时间偏移的时候会有问题,这也是当时有最大争论的点~那会儿我也给绕晕了,怀疑是否没考虑完整…概念
- 结论:一切基于timestamp的只有在需要转换成string,或者从string转换的时候才需要考虑localtime问题
- timestamp 本身是 long long 类型,表示 time since epoch (1970)到当前时间经历的秒数(seconds)0时区的
- 也就是 timestamp 永远是个相对数值量
- 无论是判断两个 timestamp 是否是同一天、同一月、年,只要都是一种规则的偏移,判断一定是准确的,小学数学:
[(x + a), (x + b)]
的关系和[(x + 8hours + a), (x + 8hours + b)]
在数值比较运算上没有区别…. - 后来他给了我他的测试用例(大佬的测试用例确实完善,很值得学习),套在我的代码上是这样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26auto _00 = easy::datetime::from_timestamp<std::chrono::seconds>(0); // 1970-01-01 00:00:00
auto _01 = easy::datetime::from_timestamp<std::chrono::seconds>(57600); // +16 hours
auto _02 = easy::datetime::from_timestamp<std::chrono::seconds>(86400); // +24 hours
auto _03 = easy::datetime::from_timestamp<std::chrono::seconds>(90000); // +25 hours
auto _04 = easy::datetime::from_timestamp<std::chrono::seconds>(144000); // +1 days 16 hours
auto _05 = easy::datetime::from_timestamp<std::chrono::seconds>(172800); // +2 days
auto _06 = easy::datetime::from_timestamp<std::chrono::seconds>(28800 - 28800); // 0
auto _07 = easy::datetime::from_timestamp<std::chrono::seconds>(57600 - 28800); // +16 hours - 8 hours
auto _08 = easy::datetime::from_timestamp<std::chrono::seconds>(86400 - 28800); // +24 hours - 8 hours
auto _09 = easy::datetime::from_timestamp<std::chrono::seconds>(90000 - 28800); // +25 hours - 8 hours
auto _10 = easy::datetime::from_timestamp<std::chrono::seconds>(144000 - 28800); // +40 hours - 8 hours
auto _11 = easy::datetime::from_timestamp<std::chrono::seconds>(172800 - 28800); // +48 hours - 8 hours
std::cout << "local: " << easy::datetime::localtime_string(_00) << " utc: " << easy::datetime::utc_string(_00) << " // 0" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_01) << " utc: " << easy::datetime::utc_string(_01) << " // +16 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_02) << " utc: " << easy::datetime::utc_string(_02) << " // +24 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_03) << " utc: " << easy::datetime::utc_string(_03) << " // +25 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_04) << " utc: " << easy::datetime::utc_string(_04) << " // +1 days 16 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_05) << " utc: " << easy::datetime::utc_string(_05) << " // +2 days" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_06) << " utc: " << easy::datetime::utc_string(_06) << " // 0" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_07) << " utc: " << easy::datetime::utc_string(_07) << " // +16 hours - 8 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_08) << " utc: " << easy::datetime::utc_string(_08) << " // +24 hours - 8 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_09) << " utc: " << easy::datetime::utc_string(_09) << " // +25 hours - 8 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_10) << " utc: " << easy::datetime::utc_string(_10) << " // +40 hours - 8 hours" << std::endl;
std::cout << "local: " << easy::datetime::localtime_string(_11) << " utc: " << easy::datetime::utc_string(_11) << " // +48 hours - 8 hours" << std::endl; - 后面在他的建议上加了一些相对时间的函数,看了c++20新增的一些 help types,加了
std::chrono::days
的写法1
2
3using days = std::chrono::duration<long long, std::ratio_multiply<std::ratio<24>, hours::period>>;
// weak 这样子~这个也比较常用
using days = std::chrono::duration<long long, std::ratio_multiply<std::ratio<7>, days::period>>;
- 新标准下的 c++ 未来可期!
- todo: 后面有办法了还是要优化下从字符串解析的性能