#include #include "../shared/MiscSupport.h" #include "FormatTime.h" // We assume local time is Pacific. Some of these things always use Eastern, // so that's 3 hours difference. #define EASTERN_OFFSET (3*60*60) inline bool isDigit(char ch) { return (ch >= '0') && (ch <= '9'); } static bool looksLikeMySql(std::string const &s) { if (s.size() != 19) return false; char const *ch = s.c_str(); if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (*ch++ != '-') return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (*ch++ != '-') return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (*ch++ != ' ') return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (*ch++ != ':') return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; if (*ch++ != ':') return false; if (!isDigit(*ch++)) return false; if (!isDigit(*ch++)) return false; return true; } int getInt(char const *&ch, int digits) { int result = 0; while (digits--) { result *= 10; result += (*ch++) - '0'; } return result; } time_t importTime(std::string const &asString) { if (looksLikeMySql(asString)) { struct tm brokenDown; char const *ch = asString.c_str(); brokenDown.tm_year = getInt(ch, 4) - 1900; ch++; brokenDown.tm_mon = getInt(ch, 2) - 1; ch++; brokenDown.tm_mday = getInt(ch, 2); ch++; brokenDown.tm_hour = getInt(ch, 2); ch++; brokenDown.tm_min = getInt(ch, 2); ch++; brokenDown.tm_sec = getInt(ch, 2); brokenDown.tm_isdst = -1; // unknown. return mktime(&brokenDown) - EASTERN_OFFSET; } else return strtollDefault(asString, 0); } // If forceEastern is false, we just convert the integer to a string. If // forceEastern is true, we export it in the mysql format and use eastern time. // If time_t is 0, regardless of forceEastern, we return the empty string. std::string exportTime(time_t asUnix, bool forceEastern) { if (asUnix <= 0) return ""; else if (forceEastern) { asUnix += EASTERN_OFFSET; struct tm brokenDown; localtime_r(&asUnix, &brokenDown); // 72 bytes seems like overkill, but that keeps some versions of the // compiler from giving me a warning. This is just a normal mysql // date and time, like "2020-05-13 14:04:19". char buffer[72]; sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d", (int)brokenDown.tm_year + 1900, (int)brokenDown.tm_mon + 1, (int)brokenDown.tm_mday, (int)brokenDown.tm_hour, (int)brokenDown.tm_min, (int)brokenDown.tm_sec); return buffer; } else return ntoa(asUnix); } #ifdef UNIT_TEST_FORMAT_TIME // g++ -Wall -O4 -o format_time_test -DUNIT_TEST_FORMAT_TIME FormatTime.C ../shared/MiscSupport.C #include int main(int, char**) { while (std::cin) { std::cout<<"Time? "; std::string line; getline(std::cin, line); if (!std::cin) { std::cout<<'\n'; break; } const time_t t = importTime(line); std::cout<<"Export unix: "<