前言 - time 简单需求
时间业务相关代码. 基本属于框架的最底层. 涉及的变动都很小. 以前参与游戏研发时候,
这方面需求不少, 各种被策划花式吊打. 转行开发互联网服务之后很少遇到这方面需求.
但是封装基础库的时候, 这方面好用api 功能是需要的. 在这就抛砖引玉简单包一层.
首先看 time 库的封装有那些基础需求.
0. 线程安全
1. 时间串 和 时间戳互换
2. 时间比较 ... 例如是否在同一天
3. 毫秒精度时间串支持
一切从简单出发, 通过上面需求, 带着大家展开作者的思路.
times.h
#ifndef _H_TIMES #define _H_TIMES #include <time.h> #include <stdbool.h> // // 1s = 1000ms = 1000000us = 1000000000ns // 1秒 1000毫秒 1000000微秒 1000000000纳秒 // ~ 力求最小时间业务单元 ~ // #ifdef __GNUC__ #include <unistd.h> #include <sys/time.h> // // msleep - 睡眠函数, 颗粒度是毫秒. // m : 待睡眠的毫秒数 // return : void // inline void msleep(int ms) { usleep(ms * 1000); } #endif #ifdef _MSC_VER #include <windows.h> inline void msleep(int ms) { Sleep(ms); } // // localtime_r - 安全的得到当前时间结构体 // timep : 输入的时间戳指针 // result : 返回输出时间结构 // return : 失败 NULL, 正常返回 result // inline struct tm * localtime_r(const time_t * timep, struct tm * result) { return localtime_s(result, timep) ? NULL : result; } #endif // times_t - 时间串类型 #define INT_TIMES (64) typedef char times_t[INT_TIMES]; #endif//_H_TIMES
我们这里通过采用 localtime_r 解决 time_t 获取线程安全问题.
稍微扯一点 其实这里 winds localtime_s 设计思路好于 localtime_r.
_Check_return_wat_ static __inline errno_t __CRTDECL localtime_s( _Out_ struct tm* const _Tm, _In_ time_t const* const _Time ) { return _localtime64_s(_Tm, _Time); }
errno_t 显然比 struct tm * 判断语义判断更加精确. 但从已经确定 time_t 实现角度出发. 更好接口设计应该是这样的
errno_t localtime_s(time_t t, struct tm * result);
毕竟 time_t 传入结构就足够. 第 0 个需求 线程安全 就搞定了.
哈哈 看着 __GUNC__ _MSC_VER 突然想笑, 未来也许引进 __clang__. 程序员 = 同类玩同类的生物
正文 - time 简单思路
1. 时间串 和 时间戳 互换. 不妨直接从函数实现角度出发. 可以分为两部
i) 时间串 parse -> struct tm
ii) struct tm -> time_t
先看第 i 步思路
// times_tm - 从时间串中提取出来年月日时分秒 bool times_tm(times_t tsr, struct tm * pm) { int c, num, * es, * py; if ((!tsr) || !(c = *tsr) || c < '0' || c > '9') return false; num = 0; es = &pm->tm_sec; py = &pm->tm_year; do { if (c >= '0' && c <= '9') { num = 10 * num + c - '0'; c = *++tsr; continue; } *py-- = num; if (py < es) break; // 去掉特殊字符, 重新开始 for (;;) { if ((c = *++tsr) == '