分布式人力发电:从监狱单车到社区能源的技术实现与应用场景
2026/5/8 18:32:11
前段时间在项目里碰到一个挺常见、但又特别容易写烂的需求:
统计时间。
听起来很简单,但一旦加上这几个条件,事情立刻变复杂:
如果你随手用定时器或者不断累加,很快就会发现:
时间开始不对劲了。
要么多算了暂停时间,要么暂停几次之后就彻底乱套。
后来我索性停下来,重新想了一下:
时间这东西,真的有必要一直“加”吗?
最后我用的方案其实很简单:
于是就有了下面这个TimeManager。
先写一个获取当前秒时间戳的小工具,用的是 C++ 自带的std::chrono:
#include<chrono>staticuint64_tgetNowSeconds(){returnstd::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();}然后是整个时间管理类:
classTimeManager{public:TimeManager():totalTime(0),segmentStartTime(0),segmentPauseTotal(0),totalPauseTotal(0),pauseStartTime(0),isPaused(false){}voidstartSegment(){segmentStartTime=getNowSeconds();segmentPauseTotal=0;isPaused=false;pauseStartTime=0;}voidpause(){if(isPaused||segmentStartTime==0)return;isPaused=true;pauseStartTime=getNowSeconds();}voidresume(){if(!isPaused||pauseStartTime==0)return;uint64_tnow=getNowSeconds();uint64_tpauseDuration=now-pauseStartTime;segmentPauseTotal+=pauseDuration;totalPauseTotal+=pauseDuration;isPaused=false;pauseStartTime=0;}voidstopSegment(){if(segmentStartTime==0)return;totalTime+=getSegmentTime();segmentStartTime=0;segmentPauseTotal=0;isPaused=false;pauseStartTime=0;}uint64_tgetSegmentTime()const{if(segmentStartTime==0)return0;uint64_tendTime=isPaused?pauseStartTime:getNowSeconds();returnendTime-segmentStartTime-segmentPauseTotal;}uint64_tgetTotalTime()const{returntotalTime+getSegmentTime();}private:uint64_ttotalTime;uint64_tsegmentStartTime;uint64_tsegmentPauseTotal;uint64_ttotalPauseTotal;uint64_tpauseStartTime;boolisPaused;};代码不长,但逻辑我挺满意的。
一句话概括就是:
总时间 = 已结束分段的时间 + 当前分段实时算出来的时间
这里有几个我刻意分开的概念。
uint64_ttotalTime;这个值只在一个地方改:stopSegment()
也就是说,只有当我明确“这个分段结束了”,
它的有效时间才会被加到总时间里。
中途暂停、恢复、怎么折腾,都不碰它。
分段有效时间的公式其实很直白:
当前时间 - 分段开始时间 - 分段暂停时间对应的代码就是:
uint64_tendTime=isPaused?pauseStartTime:getNowSeconds();returnendTime-segmentStartTime-segmentPauseTotal;有一个细节我当时特意处理了:
如果正在暂停,时间直接冻结。
所以暂停多久,分段时间就真的一秒都不涨。
我见过不少代码,是在 pause 的时候就开始各种计算,
最后状态一多就完全兜不住。
我这里的逻辑很简单:
uint64_tpauseDuration=now-pauseStartTime;segmentPauseTotal+=pauseDuration;这样不管你暂停多少次,都不会乱。
比如这样一段流程:
TimeManager tm;tm.startSegment();// 干活// 10 秒tm.pause();// 停一下// 5 秒tm.resume();// 接着干// 8 秒tm.stopSegment();// 收工最后得到的结果是:
暂停没有“偷”走任何有效时间。
时间统计这东西,最怕的不是代码写得少,而是状态太多。
后来我发现,只要记住一句话,问题就好解决很多:
能用时间戳算出来的,就别用变量去维护。
这个TimeManager本质上不是计时器,
而是一个时间状态管理器。
如果你做的是:
这种思路基本都能直接套。
如果你对那些功能更感兴趣,也可以留言告诉我。