大家好,我是阿赵。
这次来看看UE引擎使用C++来控制时间和日期相关的方法。
一、获取日期时间
时间的获取基本上都是用FDateTime
获取当前的:
FDateTime::Now()
显示日期时间举例:
FDateTime dt = FDateTime::Now();
UE_LOG(LogTemp, Display, TEXT("当前时间:%d年%d月%d日%d时%d分%d秒"), dt.GetYear(), dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(), dt.GetSecond());
二、获取时间戳
时间戳是指从1970年1月1日凌晨开始算起到现在的秒数,或者毫秒数。
获取时间戳的方法有几种:
1、std::chrono
#include <chrono>
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
这个方法需要include ,但有个问题是会有时区问题,获取完之后还需要自己加上系统所在地的时区。
2、FDateTime时间相减
毫秒
(FDateTime::Now() - FDateTime(1970, 1, 1)).GetTotalMilliseconds();
秒
(FDateTime::Now() - FDateTime(1970, 1, 1)).GetTotalSeconds();
这个方法暂时没发现没什么问题
3、ToUnixTimestamp
FDateTime::Now().ToUnixTimestamp();
这个方法只能获得秒级时间戳
三、时间戳转日期时间
从时间戳转FDateTime:
FDateTime dt = FDateTime::FromUnixTimestamp(int32 t);
注意这个方法接受的时间戳是秒级的。
四、计时器
自带的计时器方法使用SetTimer方法来实现
举例:
倒计时5秒:
GetWorldTimerManager().SetTimer(timerHandle, this, &OnTime, 5);
其中OnTime是回调函数,5是指5秒钟后执行
每2秒钟执行一次,首次执行延时5秒:
GetWorldTimerManager().SetTimer(timerHandle, this, &OnTime,2,true,5);
其中OnTime是回调函数,2是执行的频率,true是是否循环,5是首次执行时的延时
五、自定义时间管理类
我一直喜欢自己定义时间管理的工具,所以写了这么一个工具类,里面包含了获取时间、时间戳、时间戳转时间、使用倒计时、Deadline、每隔多少频率执行等等方法,不是使用SetTimer来实现,而是自己控制Tick和当前时间的关系来做时间控制:
AzhaoTimeMgr.h
#pragma once#include "CoreMinimal.h"
#include "TimeCtrlData.h"
#include "TimeEventType.h"
/*** */class UECPPTEST_API AzhaoTimeMgr
{
public://DECLARE_DELEGATE_OneParam(TimeCompleteHandler, int);//DECLARE_DELEGATE_TwoParams(TimeEveryHandler, int, int);static void Tick(); /// <summary>/// 获取AzhaoTimeMgr单例/// </summary>/// <returns></returns>static AzhaoTimeMgr* GetInstance();/// <summary>/// 获取当前时间/// </summary>/// <returns></returns>static FDateTime GetDateTime();/// <summary>/// 通过秒级时间戳获得当前时间/// </summary>/// <param name="t"></param>/// <returns></returns>static FDateTime GetDateTimeFromTimestamp(int64 t);/// <summary>/// 通过毫秒级时间戳获得当前时间/// </summary>/// <param name="t"></param>/// <returns></returns>static FDateTime GetDateTimeFromTimestampMs(int64 t);/// <summary>/// 获取系统毫秒级时间戳/// </summary>/// <returns></returns>static int64 GetSystemTime();/// <summary>/// 获取游戏秒级时间戳/// </summary>/// <returns></returns>static int64 GetNowTime();/// <summary>/// 获取游戏毫秒级时间戳/// </summary>/// <returns></returns>static int64 GetNowTimeMs();/// <summary>/// 获取当前帧的事件,单位毫秒/// </summary>/// <returns></returns>static int64 GetFrameTime();/// <summary>/// 设置服务器时间戳/// </summary>/// <param name="t">服务器时间戳,单位毫秒</param>static void SetServerTime(int64 t);/// <summary>/// 设置秒级deadLine/// </summary>/// <param name="deadLine">秒级deadLine</param>/// <param name="completeHandler">完成回调</param>/// <param name="everyHandler">每秒回调</param>/// <returns></returns>static int64 SetDeadLine(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64) = nullptr);/// <summary>/// 设置毫秒级deadLine/// </summary>/// <param name="deadLine">毫秒级deadLine</param>/// <param name="completeHandler">完成回调</param>/// <param name="everyHandler">每秒回调</param>/// <returns></returns>static int64 SetDeadLineMs(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64) = nullptr);/// <summary>/// 设置秒级倒计时/// </summary>/// <param name="t">倒计时秒数</param>/// <param name="completeHandler">完成时回调</param>/// <param name="everyHandler">每秒钟回调</param>/// <returns></returns>static int64 SetCountDown(int64 t, void (*completeHandler)(int64), void (*everyHandler)(int64,int64) = nullptr);/// <summary>/// 设置毫秒级回调/// </summary>/// <param name="t">倒计时毫秒数</param>/// <param name="completeHandler">完成回调</param>/// <param name="everyHandler">每毫秒回调</param>/// <returns></returns>static int64 SetCountDownMs(int64 t, void (*completeHandler)(int64), void (*everyHandler)(int64,int64) = nullptr);/// <summary>/// 设置每秒执行/// </summary>/// <param name="everyHandler">每秒执行的回调</param>/// <param name="t">相隔多少秒执行一次</param>/// <returns></returns>static int64 SetEverySecond(void (*everyHandler)(int64,int64), int32 t = 1);/// <summary>/// 设置每毫秒执行/// </summary>/// <param name="everyHandler">每毫秒执行的回调</param>/// <param name="t">相隔多少毫秒执行一次</param>/// <returns></returns>static int64 SetEveryMs(void (*everyHandler)(int64,int64), int32 t = 1);/// <summary>/// 设置每分钟执行/// </summary>/// <param name="everyHandler">每分钟执行的回调</param>/// <param name="t">相隔多少分钟执行一次</param>/// <returns></returns>static int64 SetEveryMinute(void (*everyHandler)(int64,int64), int32 t = 1);/// <summary>/// 移除已添加的监听/// </summary>/// <param name="id">监听id</param>static void RemoveId(int64 id);/// <summary>/// 清除所有监听/// </summary>static void ClearData();
private:AzhaoTimeMgr();~AzhaoTimeMgr();static AzhaoTimeMgr* _instance;int64 frameTime;TMap<int64, void (*)(int64)> completeHandlers;TMap<int64, int64> completeTimes;TMap<int64, void (*)(int64,int64)> everySecondHandlers;TMap<int64, void (*)(int64,int64)> everyMillisecondHandlers;TMap<int64, void (*)(int64,int64)> everyMinuteHandlers;TMap<int64, int64> everyHandlerTimesMax;TMap<int64, int64> everyHandlerTimes;TMap<int64, TimeCtrlData> addList;int64 timeDifference = 0;int64 lastTime = 0;int64 lastMillisecond = 0;int64 lastMinute = 0;int64 timeId;bool isInit = false;bool isSetServerTime = false;int64 localFrameTime = 0;TSet<int64> delList;int64 updateId = -1;TSet<int64> checkCompleteRemoveList;int64 checkCompleteCt = -1;private:void OnUpdate();void WriteServerTime(int64 t);int64 GetTimeId();void RemoveTime(int64 id);void Init();void Add2AddList(TimeCtrlData data);int64 AddCountDown(int64 sec, void (*completeHandler)(int64), void (*everyHandler)(int64,int64));int64 AddCountDownMs(int64 sec, void (*completeHandler)(int64), void (*everyHandler)(int64,int64));int64 AddDeadLine(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64));int64 AddSecond(void (*everyHandler)(int64,int64),int32 t);int64 AddMs(void (*everyHandler)(int64,int64), int32 t);int64 AddMinute(void (*everyHandler)(int64,int64), int32 t);void AddOneTimeEvent(TimeCtrlData data);void AddDeadLineFun(TimeCtrlData data);void AddCountDownFun(TimeCtrlData data);void AddCountDownMsFun(TimeCtrlData data);void AddSecond(TimeCtrlData data);void AddMsFun(TimeCtrlData data);void AddMinuteFun(TimeCtrlData data);void Remove(int64 id);void CheckComplete(int64 t);void CheckSecond(int64 t, int64 lt);void CheckMs(int64 t, int64 lt);void CheckMinute(int64 t, int64 lt);void CheckEvery(int64 tid, void(*handle)(int64, int64), int64 leftTime, int64 addtime);bool CheckInDelList(int64 id);void CheckAdd();void CheckDel();void CheckTime();
};
AzhaoTimeMgr* AzhaoTimeMgr::_instance = nullptr;
AzhaoTimeMgr.cpp
#include "Tools/TimeMgr/AzhaoTimeMgr.h"AzhaoTimeMgr::AzhaoTimeMgr()
{frameTime = GetSystemTime();
}AzhaoTimeMgr::~AzhaoTimeMgr()
{
}#pragma region 静态方法AzhaoTimeMgr* AzhaoTimeMgr::GetInstance()
{if (_instance == nullptr){_instance = new AzhaoTimeMgr();}return _instance;
}void AzhaoTimeMgr::Tick()
{AzhaoTimeMgr::GetInstance()->OnUpdate();
}FDateTime AzhaoTimeMgr::GetDateTime()
{return FDateTime::Now();
}int64 AzhaoTimeMgr::GetSystemTime()
{ return (FDateTime::Now() - FDateTime(1970, 1, 1)).GetTotalMilliseconds();//return FDateTime::Now().ToUnixTimestamp();
}int64 AzhaoTimeMgr::GetNowTime()
{int64 t = GetSystemTime();t = (t + GetInstance()->timeDifference) / 1000;return t;
}FDateTime AzhaoTimeMgr::GetDateTimeFromTimestamp(int64 t)
{return FDateTime::FromUnixTimestamp(t);
}FDateTime AzhaoTimeMgr::GetDateTimeFromTimestampMs(int64 t)
{return FDateTime::FromUnixTimestamp(t/1000);
}int64 AzhaoTimeMgr::GetNowTimeMs()
{int64 t = GetSystemTime();t = t + GetInstance()-> timeDifference;return t;
}int64 AzhaoTimeMgr::GetFrameTime()
{return GetInstance()->frameTime;
}void AzhaoTimeMgr::SetServerTime(int64 t)
{GetInstance()->WriteServerTime(t);
}int64 AzhaoTimeMgr::SetDeadLine(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{return GetInstance()->AddDeadLine(deadLine * 1000, completeHandler, everyHandler);
}int64 AzhaoTimeMgr::SetDeadLineMs(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{return GetInstance()->AddDeadLine(deadLine , completeHandler, everyHandler);
}int64 AzhaoTimeMgr::SetCountDown(int64 t, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{return GetInstance()->AddCountDown(t, completeHandler, everyHandler);
}int64 AzhaoTimeMgr::SetCountDownMs(int64 t, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{return GetInstance()->AddCountDownMs(t, completeHandler, everyHandler);
}int64 AzhaoTimeMgr::SetEverySecond(void (*everyHandler)(int64,int64), int32 t)
{return GetInstance()->AddSecond(everyHandler, t);
}int64 AzhaoTimeMgr::SetEveryMs(void (*everyHandler)(int64,int64), int32 t)
{return GetInstance()->AddMs(everyHandler, t);
}int64 AzhaoTimeMgr::SetEveryMinute(void (*everyHandler)(int64,int64), int32 t)
{return GetInstance()->AddMinute(everyHandler, t);
}void AzhaoTimeMgr::RemoveId(int64 id)
{GetInstance()->RemoveTime(id);
}void AzhaoTimeMgr::ClearData()
{GetInstance()->Init();
}#pragma endregion 静态方法void AzhaoTimeMgr::OnUpdate()
{CheckAdd();CheckDel();CheckTime();
}void AzhaoTimeMgr::WriteServerTime(int64 t)
{if (isSetServerTime != true){lastTime = 0;lastMinute = 0;lastMillisecond = 0;isSetServerTime = true;}int64 now = AzhaoTimeMgr::GetSystemTime();timeDifference = t - now;frameTime = AzhaoTimeMgr::GetNowTimeMs();
}int64 AzhaoTimeMgr::GetTimeId()
{timeId++;return timeId;
}void AzhaoTimeMgr::RemoveTime(int64 id)
{delList.Add(id);
}void AzhaoTimeMgr::Init()
{completeHandlers.Empty();completeTimes.Empty();everySecondHandlers.Empty();everyMillisecondHandlers.Empty();everyMinuteHandlers.Empty();everyHandlerTimesMax.Empty();everyHandlerTimes.Empty();delList.Empty();timeDifference = 0;lastTime = 0;lastMillisecond = 0;lastMinute = 0;timeId = 0;isSetServerTime = false;frameTime = AzhaoTimeMgr::GetNowTimeMs();localFrameTime = AzhaoTimeMgr::GetSystemTime();addList.Empty();delList.Empty();checkCompleteRemoveList.Empty();checkCompleteCt = -1;}void AzhaoTimeMgr::Add2AddList(TimeCtrlData data)
{addList.Add(data.id, data);
}int64 AzhaoTimeMgr::AddCountDown(int64 sec, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{if (completeHandler == nullptr){return -1;}int64 tid = GetTimeId();int64 now = frameTime;int64 deadline = now + sec * 1000;TimeCtrlData data;data.id = tid;data.type = TimeEventType::countDown;data.deadLine = deadline;data.completeHandler = completeHandler;if (everyHandler != nullptr){data.everyHandler = everyHandler;}Add2AddList(data);return tid;
}int64 AzhaoTimeMgr::AddCountDownMs(int64 sec, void (*completeHandler)(int64), void (*everyHandler)(int64,int64))
{if (completeHandler == nullptr){return -1;}int64 tid = GetTimeId();int64 now = frameTime;int64 deadline = now + sec;TimeCtrlData data;data.id = tid;data.type = TimeEventType::countDownMs;data.deadLine = deadline;data.completeHandler = completeHandler;if (everyHandler != nullptr){data.everyHandler = everyHandler;}Add2AddList(data);return tid;
}int64 AzhaoTimeMgr::AddSecond(void (*everyHandler)(int64,int64),int32 t)
{if (everyHandler == nullptr){return -1;}int64 tid = GetTimeId();TimeCtrlData data;data.id = tid;data.type = TimeEventType::sec;data.everyHandler = everyHandler;data.t = t;Add2AddList(data);return tid;
}int64 AzhaoTimeMgr::AddMs(void (*everyHandler)(int64,int64), int32 t)
{if (everyHandler == nullptr){return -1;}int64 tid = GetTimeId();TimeCtrlData data;data.id = tid;data.type = TimeEventType::ms;data.everyHandler = everyHandler;data.t = t;Add2AddList(data);return tid;
}int64 AzhaoTimeMgr::AddMinute(void (*everyHandler)(int64,int64), int32 t)
{if (everyHandler == nullptr){return -1;}int64 tid = GetTimeId();TimeCtrlData data;data.id = tid;data.type = TimeEventType::minute;data.everyHandler = everyHandler;data.t = t;Add2AddList(data);return tid;
}int64 AzhaoTimeMgr::AddDeadLine(int64 deadLine, void (*completeHandler)(int64), void (*everyHandler)(int64,int64) = nullptr)
{if (deadLine < 0){return -1;}if (completeHandler == nullptr){return -1;}return -1;int64 tid = GetTimeId();TimeCtrlData data;data.id = tid;data.type = TimeEventType::deadLine;data.deadLine = deadLine;data.completeHandler = completeHandler;if (everyHandler != nullptr){data.everyHandler = everyHandler;}Add2AddList(data);return tid;
}void AzhaoTimeMgr::AddOneTimeEvent(TimeCtrlData data)
{int64 eventType = data.type;if (eventType == TimeEventType::deadLine){AddDeadLineFun(data);}else if (eventType == TimeEventType::countDown){AddCountDownFun(data);}else if (eventType == TimeEventType::countDownMs){AddCountDownMsFun(data);}else if (eventType == TimeEventType::sec){AddSecond(data);}else if (eventType == TimeEventType::ms){AddMsFun(data);}else if (eventType == TimeEventType::minute){AddMinuteFun(data);}
}void AzhaoTimeMgr::AddDeadLineFun(TimeCtrlData data)
{int64 tid = data.id;completeHandlers.Emplace(tid, data.completeHandler);completeTimes.Emplace(tid, data.deadLine);if (data.everyHandler != nullptr){everySecondHandlers.Emplace(tid, data.everyHandler);}
}void AzhaoTimeMgr::AddCountDownFun(TimeCtrlData data)
{int64 tid = data.id;completeHandlers.Emplace(tid, data.completeHandler);completeTimes.Emplace(tid, data.deadLine);if (data.everyHandler != nullptr){everySecondHandlers.Emplace(tid, data.everyHandler);}
}void AzhaoTimeMgr::AddCountDownMsFun(TimeCtrlData data)
{int64 tid = data.id;completeHandlers.Emplace(tid, data.completeHandler);completeTimes.Emplace(tid, data.deadLine);if (data.everyHandler != nullptr){everyMillisecondHandlers.Emplace(tid, data.everyHandler);}
}void AzhaoTimeMgr::AddSecond(TimeCtrlData data)
{int64 tid = data.id;everySecondHandlers.Emplace(tid, data.everyHandler);everyHandlerTimes.Emplace(tid, 0);everyHandlerTimesMax.Emplace(tid, data.t);
}void AzhaoTimeMgr::AddMsFun(TimeCtrlData data)
{int64 tid = data.id;everyMillisecondHandlers.Emplace(tid, data.everyHandler);everyHandlerTimes.Emplace(tid, 0);everyHandlerTimesMax.Emplace(tid, data.t);
}void AzhaoTimeMgr::AddMinuteFun(TimeCtrlData data)
{int64 tid = data.id;everyMinuteHandlers.Emplace(tid, data.everyHandler);everyHandlerTimes.Emplace(tid, 0);everyHandlerTimesMax.Emplace(tid, data.t);
}void AzhaoTimeMgr::Remove(int64 id)
{if (completeHandlers.Contains(id)){completeHandlers.Remove(id);}if (completeTimes.Contains(id)){completeTimes.Remove(id);}if (everySecondHandlers.Contains(id)){everySecondHandlers.Remove(id);}if (everyMillisecondHandlers.Contains(id)){everyMillisecondHandlers.Remove(id);}if (everyMinuteHandlers.Contains(id)){everyMinuteHandlers.Remove(id);}if (everyHandlerTimesMax.Contains(id)){everyHandlerTimesMax.Remove(id);}if (addList.Contains(id)){addList.Remove(id);}
}void AzhaoTimeMgr::CheckComplete(int64 t)
{if (completeHandlers.Num() == 0){return;}checkCompleteRemoveList.Empty();checkCompleteCt = -1;for (auto& item : completeHandlers){int64 key = item.Key;if (CheckInDelList(key)){continue;}if (completeTimes.Contains(key)){checkCompleteCt = completeTimes[key];if (checkCompleteCt < t){item.Value(key);checkCompleteRemoveList.Add(key);}}if (checkCompleteRemoveList.Num() > 0){for (auto& item2 : checkCompleteRemoveList){delList.Add(item2);//Remove(item2);}}}
}void AzhaoTimeMgr::CheckSecond(int64 t, int64 lt)
{if (everySecondHandlers.Num() == 0){return;}int64 passTime = lt - lastTime;if (passTime > 1000){int64 leftTime = -1;for (auto& item : everySecondHandlers){int64 key = item.Key;if (CheckInDelList(key) == true){continue;}leftTime = 0;if (completeTimes.Contains(key) == true){leftTime = (*completeTimes.Find(key)-t)/1000;}CheckEvery(item.Key, item.Value, leftTime, passTime / 1000);}lastTime = lt;}
}void AzhaoTimeMgr::CheckMs(int64 t, int64 lt)
{if (everyMillisecondHandlers.Num() == 0){return;}int64 PassTime = lt - lastMillisecond;if (PassTime > 0){int64 leftTime = 0;for (auto& item : everyMillisecondHandlers){int64 key = item.Key;if (CheckInDelList(key)){continue;}leftTime = 0;if (completeTimes.Contains(key)){leftTime = (*completeTimes.Find(key)) - t;}CheckEvery(item.Key, item.Value, leftTime, PassTime);}lastMillisecond = lt;}
}void AzhaoTimeMgr::CheckMinute(int64 t, int64 lt)
{if (everyMinuteHandlers.Num() == 0){return;}int64 passTime = lt - lastMinute;if (passTime >= 60000){int64 leftTime = 0;for (auto& item : everyMinuteHandlers){int64 key = item.Key;if (CheckInDelList(key)){continue;}leftTime = 0;if (completeTimes.Contains(key)){leftTime = (*completeTimes.Find(key) - t) / 60000;}CheckEvery(item.Key, item.Value, leftTime, passTime / 60000);}lastMinute = lt;}
}void AzhaoTimeMgr::CheckEvery(int64 tid, void(*handle)(int64, int64), int64 leftTime, int64 addtime)
{int64 tInd = 0;if (everyHandlerTimes.Contains(tid)){tInd = *everyHandlerTimes.Find(tid);}int64 tMax = 1;if (everyHandlerTimesMax.Contains(tid)){tMax = *everyHandlerTimesMax.Find(tid);} tInd = tInd + addtime;;if (tInd >= tMax){if (everyHandlerTimes.Contains(tid)){everyHandlerTimes.Remove(tid);}handle(tid, leftTime);}else{everyHandlerTimes.Emplace(tid, tInd);}}bool AzhaoTimeMgr::CheckInDelList(int64 id)
{if (delList.Num() == 0){return false;}if (delList.Contains(id)){return true;}else{return false;}
}void AzhaoTimeMgr::CheckAdd()
{int32 num = addList.Num();if (num == 0){return;}for (auto& item : addList){AddOneTimeEvent(item.Value);}addList.Empty();
}void AzhaoTimeMgr::CheckDel()
{if (delList.Num() == 0){return;}for (auto& item : delList){Remove(item);}delList.Empty();
}void AzhaoTimeMgr::CheckTime()
{frameTime = AzhaoTimeMgr::GetNowTimeMs();localFrameTime = AzhaoTimeMgr::GetSystemTime();if (lastTime == 0){lastTime = localFrameTime;}if (lastMillisecond == 0){lastMillisecond = localFrameTime;}if (lastMinute == 0){lastMinute = localFrameTime;}CheckComplete(frameTime);CheckSecond(frameTime, localFrameTime);CheckMs(frameTime, localFrameTime);CheckMinute(frameTime, localFrameTime);
}TimeCtrlData.h
#pragma once#include "CoreMinimal.h"
/*** */
class UECPPTEST_API TimeCtrlData
{
public:TimeCtrlData();~TimeCtrlData();int32 type;int64 deadLine;void(*completeHandler)(int64) = nullptr;void (*everyHandler)(int64,int64) = nullptr;int64 id;int32 t;};TimeEventType.h#pragma once#include "CoreMinimal.h"/*** */
class UECPPTEST_API TimeEventType
{
public:TimeEventType();~TimeEventType();static const int32 deadLine = 0;static const int32 countDown = 1;static const int32 countDownMs = 2;static const int32 sec = 3;static const int32 ms = 4;static const int32 minute = 5;
};