snippetcppMinor
C++ time types and format conversions
Viewed 0 times
formatconversionstimetypesand
Problem
I wrote a small header-only C++11 header for converting between various C++ time formats:
To cast one time to another you have to use
The following types are supported:
In order to read strings you also have to pass
In order get strings you have to pass format string in a second pair of parenth
// time_utils/time_cast.hpp
#ifndef TIME_CAST_HPP
#define TIME_CAST_HPP
#include
#include
#include
#include
#include
namespace time_utils {
using chrono_time = std::chrono::time_point;
// TimeProxy
template
class TimeProxy {
};
template <>
class TimeProxy {
public:
TimeProxy(std::time_t time) : _time(time) {}
std::string operator()(const char* format) {
std::stringstream ss;
ss
class TimeProxy {
public:
TimeProxy(std::time_t time) : _time(time) {}
chrono_time operator()() {
return std::chrono::system_clock::from_time_t(_time);
}
private:
std::time_t _time;
};
template <>
class TimeProxy {
public:
TimeProxy(std::time_t time) : _time(time) {}
std::time_t operator()() {
return _time;
}
private:
std::time_t _time;
};
// time_cast
template
TimeProxy time_cast(std::string in, const char* format) {
// read in to std::time_t
struct tm bk_time;
strptime(in.c_str(), format, &bk_time);
std::time_t time = mktime(&bk_time);
return TimeProxy(time);
}
template
TimeProxy time_cast(std::time_t time) {
// pass time_t directly
return TimeProxy(time);
}
template
TimeProxy time_cast(chrono_time in) {
// read in to std::time_t
std::time_t time = std::chrono::system_clock::to_time_t(in);
return TimeProxy(time);
}
}
#endifTo cast one time to another you have to use
time_utils::time_cast template function, passing target type as a template argument. The input type will be deduced:time_utils::time_cast(input_time)();The following types are supported:
std::string
std::time_t
std::chrono::time_point
In order to read strings you also have to pass
strftime format inside the first pair of parentheses:time_utils::time_cast(input_string, "%T")();In order get strings you have to pass format string in a second pair of parenth
Solution
Your template class looks useful, and the usage is made quite concise with the explicit declaration/definition of the
That's somehow replicating an interface like the standard cast implementations (
So just my 2¢ so far:
DRY
First when looking at your code, I was bothered a bit regarding the repetition of the common class layout in your specializations regarding the
Though, after factoring out your common data member to a common base class like this
I have my doubts, if that really improves the code you have already. At least it doesn't regarding less typing.
On the other hand, if there would be more common data members I'd go that way.
The refactored code can be inspected here.
Do not use a prefix
The prefix underscore is preserved for C++ standard class implementations and/or compiler internals (see more detailed info here please). Rather use a postfix underscore for naming, and distinguishing member variable and parameter names:
or
and
Consider using a
Though it's very probable that
for clarity of semantics and clearly no need for copying (at point of passing the parameter).
I know this is heavily discussed and passing by value seems to be preferred (because of standard moving behaviors should apply). Though I personally prefer the
Using a
time_cast() variants.That's somehow replicating an interface like the standard cast implementations (
static_cast<>(), reinterpret_cast<>(), etc.) do.So just my 2¢ so far:
DRY
First when looking at your code, I was bothered a bit regarding the repetition of the common class layout in your specializations regarding the
_time member variable.Though, after factoring out your common data member to a common base class like this
class TimeProxyBase {
protected:
TimeProxyBase(std::time_t time) : _time(time) {}
std::time_t _time;
};
// TimeProxy
template
class TimeProxy {
};
template <>
class TimeProxy : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
std::string operator()(const char* format) {
std::stringstream ss;
ss _time)), format);
return ss.str();
}
};
template <>
class TimeProxy : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
chrono_time operator()() {
return std::chrono::system_clock::from_time_t(this->_time);
}
};
template <>
class TimeProxy : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
std::time_t operator()() {
return this->_time;
}
};I have my doubts, if that really improves the code you have already. At least it doesn't regarding less typing.
On the other hand, if there would be more common data members I'd go that way.
The refactored code can be inspected here.
Do not use a prefix
_ underscore for your own applicationsThe prefix underscore is preserved for C++ standard class implementations and/or compiler internals (see more detailed info here please). Rather use a postfix underscore for naming, and distinguishing member variable and parameter names:
std::time_t time_;or
std::time_t time;and
TimeProxy(std::time_t time_) : time(time_) {Consider using a
const reference in the constructorThough it's very probable that
time_t might be a simple positive integer number or anyways movable type, it might be better to have an explicit const reference than copy by valueTimeProxy(const std::time_t& time_);for clarity of semantics and clearly no need for copying (at point of passing the parameter).
I know this is heavily discussed and passing by value seems to be preferred (because of standard moving behaviors should apply). Though I personally prefer the
const reference style and the actual type of time_t is unspecified according this reference.Using a
const reference shouldn't do any harm anyways (besides typing a bit more).Code Snippets
class TimeProxyBase {
protected:
TimeProxyBase(std::time_t time) : _time(time) {}
std::time_t _time;
};
// TimeProxy
template <typename T>
class TimeProxy {
};
template <>
class TimeProxy<std::string> : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
std::string operator()(const char* format) {
std::stringstream ss;
ss << std::put_time(std::localtime(&(this->_time)), format);
return ss.str();
}
};
template <>
class TimeProxy<chrono_time> : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
chrono_time operator()() {
return std::chrono::system_clock::from_time_t(this->_time);
}
};
template <>
class TimeProxy<std::time_t> : private TimeProxyBase {
public:
TimeProxy(std::time_t time) : TimeProxyBase(time) {}
std::time_t operator()() {
return this->_time;
}
};std::time_t time_;std::time_t time;TimeProxy(std::time_t time_) : time(time_) {TimeProxy(const std::time_t& time_);Context
StackExchange Code Review Q#124395, answer score: 2
Revisions (0)
No revisions yet.