ES-DE/es-core/src/utils/TimeUtil.cpp

267 lines
9 KiB
C++

// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// 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"
#include <time.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 = "00000000T000000";
}
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)
{
mTime = (time < 0) ? 0 : 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<tm*>(&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<unsigned int>(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 == "19700101T010000")
return mktime(&timeStruct);
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)
{
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<char>((year - (year % 1000)) / 1000) + '0';
*s++ = static_cast<char>(((year % 1000) - (year % 100)) / 100) + '0';
*s++ = static_cast<char>(((year % 100) - (year % 10)) / 10) + '0';
*s++ = static_cast<char>(year % 10) + '0';
} break;
// Month number [00,11]
case 'm': {
const int mon = timeStruct.tm_mon + 1;
*s++ = static_cast<char>(mon / 10) + '0';
*s++ = static_cast<char>(mon % 10) + '0';
} break;
// Day of the month [01,31]
case 'd': {
*s++ = static_cast<char>(timeStruct.tm_mday / 10) + '0';
*s++ = static_cast<char>(timeStruct.tm_mday % 10) + '0';
} break;
// Hour (24-hour clock) [00,23]
case 'H': {
*s++ = static_cast<char>(timeStruct.tm_hour / 10) + '0';
*s++ = static_cast<char>(timeStruct.tm_hour % 10) + '0';
} break;
// Minute [00,59]
case 'M': {
*s++ = static_cast<char>(timeStruct.tm_min / 10) + '0';
*s++ = static_cast<char>(timeStruct.tm_min % 10) + '0';
} break;
// Second [00,59]
case 'S': {
*s++ = static_cast<char>(timeStruct.tm_sec / 10) + '0';
*s++ = static_cast<char>(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