2024-05-31 22:59:00 -04:00
|
|
|
#ifndef RFL_TIMESTAMP_HPP_
|
|
|
|
#define RFL_TIMESTAMP_HPP_
|
|
|
|
|
|
|
|
#include <ctime>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
|
|
|
#include <iterator>
|
|
|
|
#include <locale>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "Result.hpp"
|
|
|
|
#include "internal/StringLiteral.hpp"
|
|
|
|
|
|
|
|
namespace rfl {
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// For serializing and deserializing time stamps.
|
|
|
|
template <internal::StringLiteral _format>
|
|
|
|
class Timestamp {
|
|
|
|
constexpr static const internal::StringLiteral format_ = _format;
|
|
|
|
|
|
|
|
public:
|
|
|
|
using Format = rfl::Literal<_format>;
|
|
|
|
|
|
|
|
using ReflectionType = std::string;
|
|
|
|
|
|
|
|
Timestamp(const char* _str) : tm_(std::tm {}) {
|
|
|
|
const auto r = strptime(_str, _format.str().c_str(), &tm_);
|
|
|
|
if (r == NULL) {
|
2024-06-08 15:53:06 -04:00
|
|
|
throw std::runtime_error(
|
|
|
|
"String '" + std::string(_str) + "' did not match format '" +
|
|
|
|
Format().str() + "'."
|
|
|
|
);
|
2024-06-08 14:10:59 -04:00
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
}
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Timestamp(const std::string& _str) : Timestamp(_str.c_str()) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
Timestamp(const std::tm& _tm) : tm_(_tm) {}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
~Timestamp() = default;
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Returns a result containing the timestamp when successful or an Error
|
|
|
|
/// otherwise.
|
|
|
|
static Result<Timestamp> from_string(const char* _str) noexcept {
|
|
|
|
try {
|
|
|
|
return Timestamp(_str);
|
|
|
|
} catch (std::exception& e) { return Error(e.what()); }
|
2024-05-31 22:59:00 -04:00
|
|
|
}
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Returns a result containing the timestamp when successful or an Error
|
|
|
|
/// otherwise.
|
|
|
|
static Result<Timestamp> from_string(const std::string& _str) {
|
|
|
|
return from_string(_str.c_str());
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Necessary for the serialization to work.
|
|
|
|
ReflectionType reflection() const {
|
|
|
|
char outstr[200];
|
|
|
|
strftime(outstr, 200, format_.str().c_str(), &tm_);
|
|
|
|
return std::string(outstr);
|
|
|
|
}
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Expresses the underlying timestamp as a string.
|
|
|
|
std::string str() const { return reflection(); }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Trivial accessor to the underlying time stamp.
|
|
|
|
std::tm& tm() { return tm_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
/// Trivial (const) accessor to the underlying time stamp.
|
|
|
|
const std::tm& tm() const { return tm_; }
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
private:
|
2024-05-31 22:59:00 -04:00
|
|
|
#ifdef _MSC_VER
|
2024-06-08 14:10:59 -04:00
|
|
|
// This workaround is necessary, because MSVC doesn't support strptime.
|
|
|
|
char* strptime(const char* _s, const char* _f, std::tm* _tm) {
|
|
|
|
std::istringstream input(_s);
|
|
|
|
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
|
|
|
input >> std::get_time(_tm, _f);
|
|
|
|
if (input.fail()) { return NULL; }
|
|
|
|
return (char*)(_s + input.tellg());
|
2024-05-31 22:59:00 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
private:
|
|
|
|
/// The underlying time stamp.
|
|
|
|
std::tm tm_;
|
|
|
|
};
|
2024-05-31 22:59:00 -04:00
|
|
|
|
2024-06-08 14:10:59 -04:00
|
|
|
} // namespace rfl
|
2024-05-31 22:59:00 -04:00
|
|
|
|
|
|
|
#endif
|