// SPDX-License-Identifier: MIT // // ES-DE Frontend // TimeUtil.cpp // // Low-level date and time functions. // Set and get time, format to string formats, count days and months etc. // #include "utils/TimeUtil.h" namespace Utils { namespace Time { DateTime::DateTime() { mTime = 0; #if defined(_WIN64) mTimeStruct = {0, 0, 0, 1, 0, 0, 0, 0, -1}; #else mTimeStruct = {0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0}; #endif mIsoString = "19000101T000000"; } DateTime::DateTime(const time_t& time) { // Set time. setTime(time); } DateTime::DateTime(const tm& timeStruct) { // Set time struct. setTimeStruct(timeStruct); } DateTime::DateTime(const std::string& isoString) { // Set ISO string. setIsoString(isoString); } void DateTime::setTime(const time_t& time) { // Workaround to handle Unix epoch for different time zones. if (time < 82800) mTime = 0; else mTime = time; #if defined(_WIN64) localtime_s(&mTimeStruct, &mTime); #else localtime_r(&mTime, &mTimeStruct); #endif mIsoString = timeToString(mTime); } void DateTime::setTimeStruct(const tm& timeStruct) { // Set time based on struct. setTime(mktime(const_cast(&timeStruct))); } void DateTime::setIsoString(const std::string& isoString) { // Set time based on ISO string. setTime(stringToTime(isoString)); } Duration::Duration(const time_t& time) { mTotalSeconds = static_cast(time); mDays = (mTotalSeconds - (mTotalSeconds % (60 * 60 * 24))) / (60 * 60 * 24); mHours = ((mTotalSeconds % (60 * 60 * 24)) - (mTotalSeconds % (60 * 60))) / (60 * 60); mMinutes = ((mTotalSeconds % (60 * 60)) - (mTotalSeconds % (60))) / 60; mSeconds = mTotalSeconds % 60; } time_t now() { time_t time; ::time(&time); return time; } time_t stringToTime(const std::string& string, const std::string& format) { const char* s {string.c_str()}; const char* f {format.c_str()}; #if defined(_WIN64) tm timeStruct = {0, 0, 0, 1, 0, 0, 0, 0, -1}; #else tm timeStruct = {0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0}; #endif size_t parsedChars = 0; if (string == "19700101T000000") return 0; while (*f && (parsedChars < string.length())) { if (*f == '%') { f++; switch (*f++) { // Year, including century [1970,xxxx] case 'Y': { if ((parsedChars + 4) <= string.length()) { timeStruct.tm_year = (*s++ - '0') * 1000; timeStruct.tm_year += (*s++ - '0') * 100; timeStruct.tm_year += (*s++ - '0') * 10; timeStruct.tm_year += (*s++ - '0'); if (timeStruct.tm_year >= 1900) timeStruct.tm_year -= 1900; } parsedChars += 4; } break; // Month number [01,12] case 'm': { if ((parsedChars + 2) <= string.length()) { timeStruct.tm_mon = (*s++ - '0') * 10; timeStruct.tm_mon += (*s++ - '0'); if (timeStruct.tm_mon >= 1) timeStruct.tm_mon -= 1; } parsedChars += 2; } break; // Day of the month [01,31] case 'd': { if ((parsedChars + 2) <= string.length()) { timeStruct.tm_mday = (*s++ - '0') * 10; timeStruct.tm_mday += (*s++ - '0'); } parsedChars += 2; } break; // Hour (24-hour clock) [00,23] case 'H': { if ((parsedChars + 2) <= string.length()) { timeStruct.tm_hour = (*s++ - '0') * 10; timeStruct.tm_hour += (*s++ - '0'); } parsedChars += 2; } break; // Minute [00,59] case 'M': { if ((parsedChars + 2) <= string.length()) { timeStruct.tm_min = (*s++ - '0') * 10; timeStruct.tm_min += (*s++ - '0'); } parsedChars += 2; } break; // Second [00,59] case 'S': { if ((parsedChars + 2) <= string.length()) { timeStruct.tm_sec = (*s++ - '0') * 10; timeStruct.tm_sec += (*s++ - '0'); } parsedChars += 2; } break; } } else { s++; f++; } } return mktime(&timeStruct); } std::string timeToString(const time_t& time, const std::string& format) { // Workaround to handle Unix epoch for different time zones. if (time < 82800) return "19700101T000000"; const char* f {format.c_str()}; tm timeStruct; #if defined(_WIN64) localtime_s(&timeStruct, &time); #else localtime_r(&time, &timeStruct); #endif char buf[256] = {'\0'}; char* s = buf; while (*f) { if (*f == '%') { f++; switch (*f++) { // Year, including century [1970,xxxx] case 'Y': { const int year = timeStruct.tm_year + 1900; *s++ = static_cast((year - (year % 1000)) / 1000) + '0'; *s++ = static_cast(((year % 1000) - (year % 100)) / 100) + '0'; *s++ = static_cast(((year % 100) - (year % 10)) / 10) + '0'; *s++ = static_cast(year % 10) + '0'; } break; // Month number [00,11] case 'm': { const int mon = timeStruct.tm_mon + 1; *s++ = static_cast(mon / 10) + '0'; *s++ = static_cast(mon % 10) + '0'; } break; // Day of the month [01,31] case 'd': { *s++ = static_cast(timeStruct.tm_mday / 10) + '0'; *s++ = static_cast(timeStruct.tm_mday % 10) + '0'; } break; // Hour (24-hour clock) [00,23] case 'H': { *s++ = static_cast(timeStruct.tm_hour / 10) + '0'; *s++ = static_cast(timeStruct.tm_hour % 10) + '0'; } break; // Minute [00,59] case 'M': { *s++ = static_cast(timeStruct.tm_min / 10) + '0'; *s++ = static_cast(timeStruct.tm_min % 10) + '0'; } break; // Second [00,59] case 'S': { *s++ = static_cast(timeStruct.tm_sec / 10) + '0'; *s++ = static_cast(timeStruct.tm_sec % 10) + '0'; } break; } } else { *s++ = *f++; } *s = '\0'; } return std::string(buf); } int daysInMonth(const int year, const int month) { #if defined(_WIN64) tm timeStruct {0, 0, 0, 0, month, year - 1900, 0, 0, -1}; #else tm timeStruct {0, 0, 0, 0, month, year - 1900, 0, 0, -1, 0, 0}; #endif mktime(&timeStruct); return timeStruct.tm_mday; } int daysInYear(const int year) { #if defined(_WIN64) tm timeStruct {0, 0, 0, 0, 0, year - 1900 + 1, 0, 0, -1}; #else tm timeStruct {0, 0, 0, 0, 0, year - 1900 + 1, 0, 0, -1, 0, 0}; #endif mktime(&timeStruct); return timeStruct.tm_yday + 1; } } // namespace Time } // namespace Utils