This commit is contained in:
Matthias Janetschek
2015-05-27 17:41:04 +02:00
parent 52ae80523c
commit 7a479433d6
9 changed files with 613 additions and 394 deletions
@@ -0,0 +1,52 @@
#pragma once
#include <chrono>
#include <string>
#include <sstream>
#include <cstdio>
#include <ctime>
namespace hos {
namespace utils {
/*
* It took me way too long to come up with this solution (which I only consider as workaround,
* but currently it seems to be the best solution).
* There definitely needs to be much better support for timestamp-to-string conversion in C++,
* the current situation is way too unsatisfying. And boost isn't much of a help either.
*/
template<class _CLOCK>
std::string timestamp_to_ISO8601(const std::chrono::time_point<_CLOCK>& timestamp) {
std::stringstream ss;
std::tm tm_time;
char temp[256];
// First convert timestamp to time_t (loosing precision)
std::time_t time = std::chrono::system_clock::to_time_t(timestamp);
// Then convert time_t to tm_time
localtime_r(&time, &tm_time);
// Print first part of ISO8601 string
std::strftime(temp, sizeof(temp), "%FT%H:%M:", &tm_time);
ss << temp;
// Get lost precision by converting out time_t back to a timestamp and substracting it from our given timestamp,
// and add seconds to avoid the "0.xyz" problem
std::chrono::duration<double> msecs = timestamp - std::chrono::system_clock::from_time_t(time) + std::chrono::seconds(tm_time.tm_sec);
// Print seconds part of ISO8601 string
std::snprintf(temp, sizeof(temp), "%09.6f", msecs.count()); // is more compact than C++ counterpart
std::string secpart(temp);
std::replace(secpart.begin(), secpart.end(), '.', ',' ); // ISO 8601 prefers ',' over '.' as decimal mark.
ss << secpart;
// Get and print timezone part of ISO8601 string
std::strftime(temp, sizeof(temp), "%z", &tm_time);
ss << temp;
return ss.str();
}
} // namespace libvariant
} // namespace hos