KSS Utility
C++ general utilities
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
timeutil.hpp
Go to the documentation of this file.
1 //
2 // timeutil.hpp
3 // kssutil
4 //
5 // Created by Steven W. Klassen on 2013-01-04.
6 // Copyright (c) 2013 Klassen Software Solutions. All rights reserved.
7 // Licensing follows the MIT License.
8 //
9 
15 #ifndef kssutil_timeutil_hpp
16 #define kssutil_timeutil_hpp
17 
18 #include <cassert>
19 #include <chrono>
20 #include <cmath>
21 #include <cstring>
22 #include <functional>
23 #include <istream>
24 #include <locale>
25 #include <ostream>
26 #include <stdexcept>
27 #include <string>
28 #include <type_traits>
29 
30 namespace kss { namespace util { namespace time {
31 
42  template <class ToDuration, class Rep, class Period>
43  ToDuration checkedDurationCast(const std::chrono::duration<Rep, Period>& dtn) {
44  using namespace std::chrono;
45  using S = duration<long double, typename ToDuration::period>;
46  constexpr S minimumAllowed = ToDuration::min();
47  constexpr S maximumAllowed = ToDuration::max();
48  const S s = dtn;
49  if (s < minimumAllowed || s > maximumAllowed) {
50  throw std::overflow_error("checked_duration_cast");
51  }
52  return duration_cast<ToDuration>(s);
53  }
54 
55  namespace _private {
56  std::string format(const std::string &fmt, const struct tm &tm) noexcept;
57 
58  struct tm& parseIso8601(const std::string& timestr,
59  struct tm& tm,
60  std::chrono::nanoseconds& ns);
61 
62  std::string toIso8601(const struct tm& tm,
63  const std::chrono::nanoseconds& ns);
64 
65  time_t parseLocalized(const std::string& s,
66  const std::locale& loc,
67  const std::string& tzone);
68 
69  std::string toLocalized(time_t t,
70  const std::locale& loc,
71  const std::string& tzone);
72 
73  time_t readFromInputStream(std::istream& strm);
74  time_t tmToTimeT(const struct tm* tm);
75  struct tm* tzTimeR(const time_t* timep, struct tm* result, const char* tzone, char** tzout);
76  }
77 
98  inline std::string formatIso8601(const struct tm& tm) noexcept {
99  return _private::format("%FT%TZ", tm);
100  }
101  inline struct tm& parseIso8601(const std::string& timestr, struct tm& tm) {
102  std::chrono::nanoseconds ns;
103  return _private::parseIso8601(timestr, tm, ns);
104  }
105 
106  template <class Duration>
107  inline struct tm& parseIso8601(const std::string& timestr, struct tm& tm, Duration& subseconds) {
108  std::chrono::nanoseconds ns;
109  _private::parseIso8601(timestr, tm, ns);
110  subseconds = checkedDurationCast<Duration>(ns);
111  return tm;
112  }
113 
117  std::chrono::milliseconds timeOfExecution(const std::function<void()>& fn);
118 
119 
120  // MARK: time_point extensions
121 
122  // Note that the TimePoint template type needs to be a type compatible with
123  // std::chrono::time_point<Clock, Duration> for some value of Clock and
124  // Duration. This is checked using the following macro. If you get errors
125  // reported on this macro, check that your argument for TimePoint is
126  // actually a time_point type.
127 # define _KSS_IS_TIMEPOINT(TP) \
128  static_assert(std::is_object<typename TP::clock>::value \
129  && std::is_object<typename TP::duration>::value, \
130  "TP must be a std::chrono::time_point<Clock, Duration>")
131 
140  template <class TimePoint>
141  inline TimePoint now(const TimePoint& = TimePoint()) {
142  _KSS_IS_TIMEPOINT(TimePoint);
143  using Clock = typename TimePoint::clock;
144  using Duration = typename TimePoint::duration;
145  const auto dur = Clock::now().time_since_epoch();
146  return TimePoint(checkedDurationCast<Duration>(dur));
147  }
148 
155  template <class TimePoint>
156  inline TimePoint fromTimeT(time_t t, const TimePoint& = TimePoint()) {
157  _KSS_IS_TIMEPOINT(TimePoint);
158  const auto secs = std::chrono::seconds(t);
159  return TimePoint(checkedDurationCast<typename TimePoint::duration>(secs));
160  }
161 
165  template <class TimePoint>
166  inline TimePoint fromTm(const struct tm& tm, const TimePoint& typeArg = TimePoint()) {
167  _KSS_IS_TIMEPOINT(TimePoint);
168  return fromTimeT(_private::tmToTimeT(&tm), typeArg);
169  }
170 
180  template <class TimePoint>
181  TimePoint fromIso8601String(const std::string& s, const TimePoint& typeArg = TimePoint()) {
182  _KSS_IS_TIMEPOINT(TimePoint);
183  struct tm tm;
184  memset(&tm, 0, sizeof(struct tm));
185  std::chrono::nanoseconds ns(0);
186  parseIso8601(s, tm, ns);
187 
188  auto t = fromTm(tm, typeArg);
189  if (ns.count() != 0) {
190  t += std::chrono::duration_cast<typename TimePoint::duration>(ns);
191  }
192  return t;
193  }
194 
210  template <class TimePoint>
211  inline TimePoint fromLocalizedString(const std::string& s,
212  const std::locale& loc = std::locale(),
213  const std::string& tzone = std::string(),
214  const TimePoint& typeArg = TimePoint())
215  {
216  _KSS_IS_TIMEPOINT(TimePoint);
217  return fromTimeT(_private::parseLocalized(s, loc, tzone), typeArg);
218  }
219 
225  template <class Clock, class Duration = typename Clock::duration>
226  time_t toTimeT(const std::chrono::time_point<Clock, Duration>& tp) {
227  using ttduration = std::chrono::duration<time_t, std::chrono::seconds::period>;
228  const auto d = checkedDurationCast<ttduration>(tp.time_since_epoch());
229  return d.count();
230  }
231 
238  template <class Clock, class Duration = typename Clock::duration>
239  struct tm& toTm(const std::chrono::time_point<Clock, Duration>& tp, struct tm& tm) {
240  const auto tt = toTimeT(tp);
241  _private::tzTimeR(&tt, &tm, nullptr, nullptr);
242  return tm;
243  }
244 
252  template <class Clock, class Duration = typename Clock::duration>
253  std::string toIso8601String(const std::chrono::time_point<Clock, Duration>& tp) {
254  struct tm tm;
255  toTm(tp, tm);
256  const auto secs = checkedDurationCast<std::chrono::seconds>(tp.time_since_epoch());
257  const auto subsecs = tp.time_since_epoch() - secs;
258  std::chrono::nanoseconds ns(0);
259  if (subsecs.count() > 0) {
260  typename Duration::period p;
261  const auto subSecsAsSeconds = (long double)subsecs.count() * p.num / p.den;
262  assert(subSecsAsSeconds <= 1); // should be a fraction of a second
263  const auto subSecsRoundedToNs = std::round(subSecsAsSeconds * 1000000000);
264  const auto rep = std::chrono::nanoseconds::rep(subSecsRoundedToNs);
265  ns = std::chrono::nanoseconds(rep);
266  }
267  return _private::toIso8601(tm, ns);
268  }
269 
281  template <class Clock, class Duration = typename Clock::duration>
282  inline std::string toLocalizedString(const std::chrono::time_point<Clock, Duration>& tp,
283  const std::locale& loc = std::locale(),
284  const std::string& tzone = std::string())
285  {
286  return _private::toLocalized(toTimeT(tp), loc, tzone);
287  }
288 
293  template <class Clock, class Duration = typename Clock::duration>
294  std::ostream& operator<<(std::ostream& strm,
295  const std::chrono::time_point<Clock, Duration>& tp)
296  {
297  const auto loc = strm.getloc();
298  strm << toLocalizedString(tp, loc);
299  return strm;
300  }
301 
306  template <class Clock, class Duration = typename Clock::duration>
307  inline std::istream& operator>>(std::istream& strm,
308  std::chrono::time_point<Clock, Duration>& tp)
309  {
310  tp = fromTimeT(_private::readFromInputStream(strm), tp);
311  return strm;
312  }
313 }}}
314 
315 #endif
TimePoint fromIso8601String(const std::string &s, const TimePoint &typeArg=TimePoint())
Definition: timeutil.hpp:181
struct tm & parseIso8601(const std::string &timestr, struct tm &tm)
Definition: timeutil.hpp:101
time_t toTimeT(const std::chrono::time_point< Clock, Duration > &tp)
Definition: timeutil.hpp:226
TimePoint fromTimeT(time_t t, const TimePoint &=TimePoint())
Definition: timeutil.hpp:156
TimePoint fromTm(const struct tm &tm, const TimePoint &typeArg=TimePoint())
Definition: timeutil.hpp:166
std::string formatIso8601(const struct tm &tm) noexcept
Definition: timeutil.hpp:98
TimePoint fromLocalizedString(const std::string &s, const std::locale &loc=std::locale(), const std::string &tzone=std::string(), const TimePoint &typeArg=TimePoint())
Definition: timeutil.hpp:211
std::chrono::milliseconds timeOfExecution(const std::function< void()> &fn)
ToDuration checkedDurationCast(const std::chrono::duration< Rep, Period > &dtn)
Definition: timeutil.hpp:43
std::string toLocalizedString(const std::chrono::time_point< Clock, Duration > &tp, const std::locale &loc=std::locale(), const std::string &tzone=std::string())
Definition: timeutil.hpp:282
std::istream & operator>>(std::istream &strm, std::chrono::time_point< Clock, Duration > &tp)
Definition: timeutil.hpp:307
std::string format(std::string pattern,...)
std::string toIso8601String(const std::chrono::time_point< Clock, Duration > &tp)
Definition: timeutil.hpp:253
TimePoint now(const TimePoint &=TimePoint())
Definition: timeutil.hpp:141
struct tm & toTm(const std::chrono::time_point< Clock, Duration > &tp, struct tm &tm)
Definition: timeutil.hpp:239
std::ostream & operator<<(std::ostream &strm, const std::chrono::time_point< Clock, Duration > &tp)
Definition: timeutil.hpp:294