diff options
author | Kargatum <dowlandtop@yandex.com> | 2022-01-19 12:01:59 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-19 12:01:59 +0700 |
commit | 259b9133f68ef0d740fc871d59fab3d2791f33b4 (patch) | |
tree | 89da4d2a14ee203de3baff62e6c2d5b4b025bbfa /src/common/Utilities/Timer.cpp | |
parent | b5ab409614bf0d45e7a4f03c57b15edf113fe5f0 (diff) |
feat(Core/Common): add new helpers for time utility (#10207)
Diffstat (limited to 'src/common/Utilities/Timer.cpp')
-rw-r--r-- | src/common/Utilities/Timer.cpp | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/src/common/Utilities/Timer.cpp b/src/common/Utilities/Timer.cpp new file mode 100644 index 0000000000..e7cb691a1c --- /dev/null +++ b/src/common/Utilities/Timer.cpp @@ -0,0 +1,442 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Timer.h" +#include "StringFormat.h" +#include <iomanip> +#include <sstream> + +namespace Acore::TimeDiff // in us +{ + constexpr uint64 MILLISECONDS = 1000; + constexpr uint64 SECONDS = 1000 * MILLISECONDS; + constexpr uint64 MINUTES = 60 * SECONDS; + constexpr uint64 HOURS = 60 * MINUTES; + constexpr uint64 DAYS = 24 * HOURS; +} + +template<> +AC_COMMON_API uint32 Acore::Time::TimeStringTo<Seconds>(std::string_view timestring) +{ + uint32 secs = 0; + uint32 buffer = 0; + uint32 multiplier = 0; + + for (char itr : timestring) + { + if (isdigit(itr)) + { + buffer *= 10; + buffer += itr - '0'; + } + else + { + switch (itr) + { + case 'd': + multiplier = DAY; + break; + case 'h': + multiplier = HOUR; + break; + case 'm': + multiplier = MINUTE; + break; + case 's': + multiplier = 1; + break; + default: + return 0; // bad format + } + + buffer *= multiplier; + secs += buffer; + buffer = 0; + } + } + + return secs; +} + +template<> +AC_COMMON_API std::string Acore::Time::ToTimeString<Microseconds>(uint64 durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + uint64 microsecs = durationTime % 1000; + uint64 millisecs = (durationTime / TimeDiff::MILLISECONDS) % 1000; + uint64 secs = (durationTime / TimeDiff::SECONDS) % 60; + uint64 minutes = (durationTime / TimeDiff::MINUTES) % 60; + uint64 hours = (durationTime / TimeDiff::HOURS) % 24; + uint64 days = durationTime / TimeDiff::DAYS; + + if (timeFormat == TimeFormat::Numeric) + { + if (days) + { + return Acore::StringFormatFmt("{}:{:02}:{:02}:{:02}:{:02}:{:02}", days, hours, minutes, secs, millisecs); + } + else if (hours) + { + return Acore::StringFormatFmt("{}:{:02}:{:02}:{:02}:{:02}", hours, minutes, secs, millisecs); + } + else if (minutes) + { + return Acore::StringFormatFmt("{}:{:02}:{:02}:{:02}", minutes, secs, millisecs); + } + else if (secs) + { + return Acore::StringFormatFmt("{}:{:02}:{:02}", secs, millisecs); + } + else if (millisecs) + { + return Acore::StringFormatFmt("{}:{:02}", millisecs); + } + else // microsecs + { + return Acore::StringFormatFmt("{}", microsecs); + } + } + + std::ostringstream ss; + std::string stringTime; + + auto GetStringFormat = [&](uint32 timeType, std::string_view shortText, std::string_view fullText1, std::string_view fullText) + { + ss << timeType; + + switch (timeFormat) + { + case TimeFormat::ShortText: + ss << shortText; + break; + case TimeFormat::FullText: + ss << (timeType == 1 ? fullText1 : fullText); + break; + default: + ss << "<Unknown time format>"; + } + }; + + if (days) + { + GetStringFormat(days, "d ", " Day ", " Days "); + } + + if (timeOutput == TimeOutput::Days) + { + stringTime = ss.str(); + } + + if (hours) + { + GetStringFormat(hours, "h ", " Hour ", " Hours "); + } + + if (timeOutput == TimeOutput::Hours) + { + stringTime = ss.str(); + } + + if (minutes) + { + GetStringFormat(minutes, "m ", " Minute ", " Minutes "); + } + + if (timeOutput == TimeOutput::Minutes) + { + stringTime = ss.str(); + } + + if (secs) + { + GetStringFormat(secs, "s ", " Second ", " Seconds "); + } + + if (timeOutput == TimeOutput::Seconds) + { + stringTime = ss.str(); + } + + if (millisecs) + { + GetStringFormat(millisecs, "ms ", " Millisecond ", " Milliseconds "); + } + + if (timeOutput == TimeOutput::Milliseconds) + { + stringTime = ss.str(); + } + + if (microsecs) + { + GetStringFormat(microsecs, "us ", " Microsecond ", " Microseconds "); + } + + if (timeOutput == TimeOutput::Microseconds) + { + stringTime = ss.str(); + } + + return Acore::String::TrimRightInPlace(stringTime); +} + +template<> +AC_COMMON_API std::string Acore::Time::ToTimeString<Milliseconds>(uint64 durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + return ToTimeString<Microseconds>(durationTime * TimeDiff::MILLISECONDS, timeOutput, timeFormat); +} + +template<> +AC_COMMON_API std::string Acore::Time::ToTimeString<Seconds>(uint64 durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + return ToTimeString<Microseconds>(durationTime * TimeDiff::SECONDS, timeOutput, timeFormat); +} + +template<> +AC_COMMON_API std::string Acore::Time::ToTimeString<Minutes>(uint64 durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + return ToTimeString<Microseconds>(durationTime * TimeDiff::MINUTES, timeOutput, timeFormat); +} + +template<> +AC_COMMON_API std::string Acore::Time::ToTimeString<Seconds>(std::string_view durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + return ToTimeString<Seconds>(TimeStringTo<Seconds>(durationTime), timeOutput, timeFormat); +} + +std::string Acore::Time::ToTimeString(Microseconds durationTime, TimeOutput timeOutput /*= TimeOutput::Seconds*/, TimeFormat timeFormat /*= TimeFormat::ShortText*/) +{ + return ToTimeString<Microseconds>(durationTime.count(), timeOutput, timeFormat); +} + +#if AC_PLATFORM == AC_PLATFORM_WINDOWS +struct tm* localtime_r(time_t const* time, struct tm* result) +{ + localtime_s(result, time); + return result; +} +#endif + +std::tm Acore::Time::TimeBreakdown(time_t time /*= 0*/) +{ + if (!time) + { + time = GetEpochTime().count(); + } + + std::tm timeLocal; + localtime_r(&time, &timeLocal); + return timeLocal; +} + +time_t Acore::Time::LocalTimeToUTCTime(time_t time) +{ +#if AC_PLATFORM == AC_PLATFORM_WINDOWS + return time + _timezone; +#else + return time + timezone; +#endif +} + +time_t Acore::Time::GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime) +{ + tm timeLocal = TimeBreakdown(time); + timeLocal.tm_hour = 0; + timeLocal.tm_min = 0; + timeLocal.tm_sec = 0; + + time_t midnightLocal = mktime(&timeLocal); + time_t hourLocal = midnightLocal + hour * HOUR; + + if (onlyAfterTime && hourLocal <= time) + { + hourLocal += DAY; + } + + return hourLocal; +} + +std::string Acore::Time::TimeToTimestampStr(Seconds time /*= 0s*/, std::string_view fmt /*= {}*/) +{ + std::stringstream ss; + std::string format{ fmt }; + time_t t = time.count(); + + if (format.empty()) + { + format = "%Y-%m-%d %X"; + } + + ss << std::put_time(std::localtime(&t), format.c_str()); + return ss.str(); +} + +std::string Acore::Time::TimeToHumanReadable(Seconds time /*= 0s*/, std::string_view fmt /*= {}*/) +{ + std::stringstream ss; + std::string format{ fmt }; + time_t t = time.count(); + + if (format.empty()) + { + format = "%a %b %d %Y %X"; + } + + ss << std::put_time(std::localtime(&t), format.c_str()); + return ss.str(); +} + +time_t Acore::Time::GetNextTimeWithDayAndHour(int8 dayOfWeek, int8 hour) +{ + if (hour < 0 || hour > 23) + { + hour = 0; + } + + tm localTm = TimeBreakdown(); + localTm.tm_hour = hour; + localTm.tm_min = 0; + localTm.tm_sec = 0; + + if (dayOfWeek < 0 || dayOfWeek > 6) + { + dayOfWeek = (localTm.tm_wday + 1) % 7; + } + + uint32 add; + + if (localTm.tm_wday >= dayOfWeek) + { + add = (7 - (localTm.tm_wday - dayOfWeek)) * DAY; + } + else + { + add = (dayOfWeek - localTm.tm_wday) * DAY; + } + + return mktime(&localTm) + add; +} + +time_t Acore::Time::GetNextTimeWithMonthAndHour(int8 month, int8 hour) +{ + if (hour < 0 || hour > 23) + { + hour = 0; + } + + tm localTm = TimeBreakdown(); + localTm.tm_mday = 1; + localTm.tm_hour = hour; + localTm.tm_min = 0; + localTm.tm_sec = 0; + + if (month < 0 || month > 11) + { + month = (localTm.tm_mon + 1) % 12; + + if (!month) + { + localTm.tm_year += 1; + } + } + else if (localTm.tm_mon >= month) + { + localTm.tm_year += 1; + } + + localTm.tm_mon = month; + return mktime(&localTm); +} + +uint32 Acore::Time::GetSeconds(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_sec; +} + +uint32 Acore::Time::GetMinutes(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_min; +} + +uint32 Acore::Time::GetHours(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_hour; +} + +uint32 Acore::Time::GetDayInWeek(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_wday; +} + +uint32 Acore::Time::GetDayInMonth(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_mday; +} + +uint32 Acore::Time::GetDayInYear(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_yday; +} + +uint32 Acore::Time::GetMonth(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_mon; +} + +uint32 Acore::Time::GetYear(Seconds time /*= 0s*/) +{ + if (time == 0s) + { + time = GetEpochTime(); + } + + return TimeBreakdown(time.count()).tm_year; +} |