Last active
April 11, 2024 13:48
-
-
Save ttldtor/6fa746139251794433e76c6efd97d155 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum TimeZone { LOCAL, GMT }; | |
// https://stackoverflow.com/a/58037981/21913386 | |
// Algorithm: http://howardhinnant.github.io/date_algorithms.html | |
int daysFromEpoch(int y, int m, int d) { | |
y -= m <= 2; | |
int era = y / 400; | |
int yoe = y - era * 400; // [0, 399] | |
int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365] | |
int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] | |
return era * 146097 + doe - 719468; | |
} | |
// It does not modify broken-down time | |
time_t timegm(struct tm const *t) { | |
int year = t->tm_year + 1900; | |
int month = t->tm_mon; // 0-11 | |
if (month > 11) { | |
year += month / 12; | |
month %= 12; | |
} else if (month < 0) { | |
int years_diff = (11 - month) / 12; | |
year -= years_diff; | |
month += 12 * years_diff; | |
} | |
int days_since_epoch = daysFromEpoch(year, month + 1, t->tm_mday); | |
return 60 * (60 * (24L * days_since_epoch + t->tm_hour) + t->tm_min) + t->tm_sec; | |
} | |
// Function to convert a tm structure to a time_point in UTC/GMT | |
std::chrono::system_clock::time_point tmToUTCTimePoint(std::tm *tm) { | |
// Construct time_t from tm as if it is UTC time | |
time_t utcTime = timegm(tm); | |
// Convert time_t to system_clock::time_point | |
return std::chrono::system_clock::from_time_t(utcTime); | |
} | |
constexpr long long INVALID_TIMESTAMP = std::numeric_limits<long long>::min(); | |
template <TimeZone> inline long long parseDateTime(const std::string &dateTimeString, const std::string &format); | |
template <> inline long long parseDateTime<LOCAL>(const std::string &dateTimeString, const std::string &format) { | |
std::tm tm = {}; | |
std::istringstream ss(dateTimeString); | |
ss >> std::get_time(&tm, format.c_str()); | |
if (ss.fail()) { | |
return INVALID_TIMESTAMP; | |
} | |
return std::chrono::system_clock::from_time_t(std::mktime(&tm)).time_since_epoch().count() * 1000; | |
} | |
template <> inline long long parseDateTime<GMT>(const std::string &dateTimeString, const std::string &format) { | |
std::tm tm = {}; | |
std::istringstream ss(dateTimeString); | |
ss >> std::get_time(&tm, format.c_str()); | |
if (ss.fail()) { | |
return INVALID_TIMESTAMP; | |
} | |
return tmToUTCTimePoint(&tm).time_since_epoch().count() * 1000; | |
} | |
/* | |
* Parse date string in formats: | |
* "%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%dT%H:%M", "%Y-%m-%d", | |
* "%d-%m-%Y %H:%M:%S", "%d-%m-%YT%H:%M:%S", "%d-%m-%Y %H:%M", "%d-%m-%YT%H:%M", "%d-%m-%Y", | |
* "%Y-%m-%d %H:%M:%SZ", "%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%d %H:%MZ", "%Y-%m-%dT%H:%MZ", "%Y-%m-%dZ", | |
* "%d-%m-%Y %H:%M:%SZ", "%d-%m-%YT%H:%M:%SZ", "%d-%m-%Y %H:%MZ", "%d-%m-%YT%H:%MZ", "%d-%m-%YZ", | |
* "<timestamp_in_millis>" | |
*/ | |
long long parseDateTime(const std::string &dateTimeString) { | |
static const std::vector<std::string> formats{ | |
"%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%dT%H:%M", "%Y-%m-%d", | |
"%d-%m-%Y %H:%M:%S", "%d-%m-%YT%H:%M:%S", "%d-%m-%Y %H:%M", "%d-%m-%YT%H:%M", "%d-%m-%Y", | |
}; | |
if (dateTimeString.size() > 1 && dateTimeString.back() == 'Z') { | |
auto dateTimeString2 = dateTimeString.substr(0, dateTimeString.size() - 1); | |
for (auto &&f : formats) { | |
auto timestamp = parseDateTime<GMT>(dateTimeString2, f); | |
if (timestamp != INVALID_TIMESTAMP) { | |
return timestamp; | |
} | |
} | |
} | |
for (auto &&f : formats) { | |
auto timestamp = parseDateTime<LOCAL>(dateTimeString, f); | |
if (timestamp != INVALID_TIMESTAMP) { | |
return timestamp; | |
} | |
} | |
long long result{}; | |
std::istringstream ss(dateTimeString); | |
ss >> result; | |
if (ss.fail()) { | |
return INVALID_TIMESTAMP; | |
} | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment