NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
DateTime/DateTime.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#ifndef NUMCPP_NO_USE_BOOST
31
32#include <chrono>
33#include <ctime>
34#include <iostream>
35#include <regex>
36#include <sstream>
37#include <stdexcept>
38#include <string>
39#include <string_view>
40
41#include "boost/date_time/posix_time/posix_time.hpp"
42
44
45namespace nc
46{
47 //================================================================================
48 // Class Description:
51 {
52 public:
53 static constexpr int MAX_MONTH = 12;
54 static constexpr int MAX_DAY = 31;
55 static constexpr int MAX_HOUR = 23;
56 static constexpr int MAX_MINUTE = 59;
57 static constexpr int MAX_SECOND = 59;
58
59 //============================================================================
60 // Method Description:
63 DateTime() = default;
64
65 //============================================================================
66 // Method Description:
71 explicit DateTime(const TimePoint& tp)
72 {
73 auto tpSubSeconds = std::chrono::duration_cast<Duration>(tp.time_since_epoch());
74 auto fractionalSecond = static_cast<double>(tpSubSeconds.count() % Duration::period::den) /
75 static_cast<double>(Duration::period::den);
76 auto time = Clock::to_time_t(std::chrono::time_point_cast<Clock::duration>(tp));
77 std::tm tm{};
78#ifdef _MSC_VER
79 gmtime_s(&tm, &time);
80#else
81 gmtime_r(&time, &tm);
82#endif
83
84 setYear(tm.tm_year + TM_EPOCH_YEAR);
85 setMonth(tm.tm_mon + 1);
86 setDay(tm.tm_mday);
87 setHour(tm.tm_hour);
88 setMinute(tm.tm_min);
89 setSecond(tm.tm_sec);
91 }
92
93 //============================================================================
94 // Method Description:
99 explicit DateTime(const std::string& timestamp) :
100 DateTime(strToTimepoint(timestamp))
101 {
102 }
103
104 //============================================================================
105 // Method Description:
116 DateTime(int year, int month, int day, int hour, int minute, int second, double fractionalSecond = 0.0) noexcept
117 :
118 year_(year),
119 month_(month),
120 day_(day),
121 hour_(hour),
122 minute_(minute),
123 second_(second),
124 fractionalSecond_(fractionalSecond)
125 {
126 }
127
128 //============================================================================
129 // Method Description:
134 [[nodiscard]] int year() const noexcept
135 {
136 return year_;
137 }
138
139 //============================================================================
140 // Method Description:
145 void setYear(int year)
146 {
147 if (year < 0)
148 {
149 throw std::invalid_argument("input year must be greater than zero");
150 }
151 year_ = year;
152 }
153
154 //============================================================================
155 // Method Description:
160 [[nodiscard]] int month() const noexcept
161 {
162 return month_;
163 }
164
165 //============================================================================
166 // Method Description:
171 void setMonth(int month)
172 {
173 if (month < 1)
174 {
175 throw std::invalid_argument("input month must be greater than one");
176 }
177 if (month > MAX_MONTH)
178 {
179 throw std::invalid_argument("input month must be less than DateTime::MAX_MONTH");
180 }
181 month_ = month;
182 }
183
184 //============================================================================
185 // Method Description:
190 [[nodiscard]] int day() const noexcept
191 {
192 return day_;
193 }
194
195 //============================================================================
196 // Method Description:
201 void setDay(int day)
202 {
203 if (day < 1)
204 {
205 throw std::invalid_argument("input day must be greater than one");
206 }
207 if (day > MAX_DAY)
208 {
209 throw std::invalid_argument("input day must be less than DateTime::MAX_DAY");
210 }
211 day_ = day;
212 }
213
214 //============================================================================
215 // Method Description:
220 [[nodiscard]] int hour() const noexcept
221 {
222 return hour_;
223 }
224
225 //============================================================================
226 // Method Description:
231 void setHour(int hour)
232 {
233 if (hour < 0)
234 {
235 throw std::invalid_argument("input hour must be greater than zero");
236 }
237 if (hour > MAX_HOUR)
238 {
239 throw std::invalid_argument("input hour must be less than DateTime::MAX_HOUR");
240 }
241 hour_ = hour;
242 }
243
244 //============================================================================
245 // Method Description:
250 [[nodiscard]] int minute() const noexcept
251 {
252 return minute_;
253 }
254
255 //============================================================================
256 // Method Description:
262 {
263 if (minute < 0)
264 {
265 throw std::invalid_argument("input minute must be greater than zero");
266 }
267 if (minute > MAX_MINUTE)
268 {
269 throw std::invalid_argument("input minute must be less than DateTime::MAX_MINUTE");
270 }
271 minute_ = minute;
272 }
273
274 //============================================================================
275 // Method Description:
280 [[nodiscard]] int second() const noexcept
281 {
282 return second_;
283 }
284
285 //============================================================================
286 // Method Description:
292 {
293 if (second < 0)
294 {
295 throw std::invalid_argument("input second must be greater than zero");
296 }
297 if (second > MAX_SECOND)
298 {
299 throw std::invalid_argument("input second must be less than DateTime::MAX_SECOND");
300 }
301 second_ = second;
302 }
303
304 //============================================================================
305 // Method Description:
310 [[nodiscard]] double fractionalSecond() const noexcept
311 {
312 return fractionalSecond_;
313 }
314
315 //============================================================================
316 // Method Description:
322 {
323 if (fractionalSecond < 0. || fractionalSecond >= 1.)
324 {
325 throw std::invalid_argument("input fractionalSecond must be in the range [0, 1)");
326 }
327 fractionalSecond_ = fractionalSecond;
328 }
329
330 //============================================================================
331 // Method Description:
336 [[nodiscard]] TimePoint toTimePoint() const
337 {
338 std::tm t{};
339 t.tm_year = year_ - TM_EPOCH_YEAR;
340 t.tm_mon = month_ - 1; // tm is 0 based months
341 t.tm_mday = day_;
342 t.tm_hour = hour_;
343 t.tm_min = minute_;
344 t.tm_sec = second_;
345 auto timePoint = Clock::from_time_t(
346#ifdef _MSC_VER
347 _mkgmtime
348#else
349 timegm
350#endif
351 (&t));
352 return std::chrono::time_point_cast<TimePoint::duration>(timePoint) +
353 std::chrono::nanoseconds(static_cast<int64_t>(fractionalSecond_ * SECONDS_TO_NANOSECONDS));
354 }
355
356 //============================================================================
357 // Method Description:
362 [[nodiscard]] std::string toStr() const
363 {
364 const auto timePoint = toTimePoint();
365 const auto timeSinceEpoch = timePoint.time_since_epoch().count();
366 time_t secondsFromEpoch = timeSinceEpoch / Duration::period::den;
367 const auto fractionalSeconds = static_cast<double>(timeSinceEpoch % Duration::period::den) /
368 static_cast<double>(Duration::period::den);
369
370 std::tm tm{};
371#ifdef _MSC_VER
372 gmtime_s(&tm, &secondsFromEpoch);
373#else
374 gmtime_r(&secondsFromEpoch, &tm);
375#endif
376
377 std::stringstream ss;
378 if (fractionalSeconds > 0)
379 {
380 const auto format = "%Y-%m-%dT%H:%M:%S.%msZ";
381 std::stringstream ssFractionalSecond;
382 ssFractionalSecond.precision(NANO_SECOND_PRECESION);
383 ssFractionalSecond << std::fixed << fractionalSeconds;
384 auto fractionalSecondStr = ssFractionalSecond.str();
385 // strip of the preceding "0." and any trailing zeros
386 fractionalSecondStr = fractionalSecondStr.substr(2, fractionalSecondStr.size());
387 fractionalSecondStr = fractionalSecondStr.substr(0, fractionalSecondStr.find_last_not_of('0') + 1);
388 const auto fractionalSecondsFormat = std::regex_replace(format, std::regex("%ms"), fractionalSecondStr);
389 ss << std::put_time(&tm, fractionalSecondsFormat.c_str());
390 }
391 else
392 {
393 const auto format = "%Y-%m-%dT%H:%M:%SZ";
394 ss << std::put_time(&tm, format);
395 }
396
397 return ss.str();
398 }
399
400 //============================================================================
401 // Method Description:
407 [[nodiscard]] static DateTime now() noexcept
408 {
409 return DateTime(Clock::now());
410 }
411
412 //============================================================================
413 // Method Description:
418 static TimePoint strToTimepoint(const std::string& timestamp)
419 {
420 const std::regex regexIsoTime{ R"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?Z)" };
421 if (!std::regex_match(timestamp, regexIsoTime))
422 {
423 throw std::invalid_argument("Invalid iso timestamp format");
424 }
425
426 auto convertedTime = boost::posix_time::ptime{};
427 try
428 {
429 convertedTime = boost::posix_time::from_iso_extended_string(timestamp.substr(0, timestamp.size() - 1));
430 }
431 catch (...)
432 {
433 throw std::invalid_argument("Invalid iso timestamp format");
434 }
435
436 const auto fromEpoch = convertedTime - POSIX_EPOCH;
437 return TimePoint{ Duration{ fromEpoch.total_nanoseconds() } };
438 }
439
440 private:
441 static constexpr int TM_EPOCH_YEAR = 1900;
442 static constexpr int POSIX_EPOCH_YEAR = 1970;
443 static inline const std::string POSIX_EPOCH_STR{ "1970-01-01T00:00:00" };
444 static inline const boost::posix_time::ptime POSIX_EPOCH{ boost::posix_time::from_iso_extended_string(
445 POSIX_EPOCH_STR) };
446 static constexpr double SECONDS_TO_NANOSECONDS = 1e9;
447 static constexpr int NANO_SECOND_PRECESION = 9;
448
450 int year_{ POSIX_EPOCH_YEAR };
452 int month_{ 1 };
454 int day_{ 1 };
456 int hour_{ 0 };
458 int minute_{ 0 };
460 int second_{ 0 };
462 double fractionalSecond_{ 0.0 };
463 };
464
465 //============================================================================
466 // Method Description:
473 [[nodiscard]] inline bool operator==(const DateTime& lhs, const DateTime& rhs) noexcept
474 {
475 return lhs.toTimePoint() == rhs.toTimePoint();
476 }
477
478 //============================================================================
479 // Method Description:
486 [[nodiscard]] inline bool operator!=(const DateTime& lhs, const DateTime& rhs) noexcept
487 {
488 return !(lhs == rhs);
489 }
490
491 //============================================================================
492 // Method Description:
499 [[nodiscard]] inline bool operator<(const DateTime& lhs, const DateTime& rhs) noexcept
500 {
501 return lhs.toTimePoint() < rhs.toTimePoint();
502 }
503
504 //============================================================================
505 // Method Description:
512 [[nodiscard]] inline bool operator<=(const DateTime& lhs, const DateTime& rhs) noexcept
513 {
514 return lhs.toTimePoint() <= rhs.toTimePoint();
515 }
516
517 //============================================================================
518 // Method Description:
525 [[nodiscard]] inline bool operator>(const DateTime& lhs, const DateTime& rhs) noexcept
526 {
527 return lhs.toTimePoint() > rhs.toTimePoint();
528 }
529
530 //============================================================================
531 // Method Description:
538 [[nodiscard]] inline bool operator>=(const DateTime& lhs, const DateTime& rhs) noexcept
539 {
540 return lhs.toTimePoint() >= rhs.toTimePoint();
541 }
542
543 //============================================================================
544 // Method Description:
551 [[nodiscard]] inline Duration operator-(const DateTime& lhs, const DateTime& rhs) noexcept
552 {
553 return lhs.toTimePoint() - rhs.toTimePoint();
554 }
555
556 //============================================================================
557 // Method Description:
564 inline std::ostream& operator<<(std::ostream& os, const DateTime& datetime) noexcept
565 {
566 os << "DateTime:\n";
567 os << "\tyear: " << datetime.year() << '\n';
568 os << "\tmonth: " << datetime.month() << '\n';
569 os << "\tday: " << datetime.day() << '\n';
570 os << "\thour: " << datetime.hour() << '\n';
571 os << "\tminute: " << datetime.minute() << '\n';
572 os << "\tsecond: " << datetime.second() << '\n';
573 os << "\tfractionalSecond: " << datetime.fractionalSecond() << '\n';
574 return os;
575 }
576} // namespace nc
577
578#endif
Date Time class for working with iso formatted date times.
Definition: DateTime/DateTime.hpp:51
void setFractionalSecond(double fractionalSecond)
fractionalSecond setter
Definition: DateTime/DateTime.hpp:321
void setHour(int hour)
hour setter
Definition: DateTime/DateTime.hpp:231
static constexpr int MAX_HOUR
Definition: DateTime/DateTime.hpp:55
int hour() const noexcept
hour getter
Definition: DateTime/DateTime.hpp:220
int second() const noexcept
second getter
Definition: DateTime/DateTime.hpp:280
DateTime()=default
TimePoint toTimePoint() const
Converts the struct to a TimePoint.
Definition: DateTime/DateTime.hpp:336
static constexpr int MAX_MINUTE
Definition: DateTime/DateTime.hpp:56
DateTime(int year, int month, int day, int hour, int minute, int second, double fractionalSecond=0.0) noexcept
Definition: DateTime/DateTime.hpp:116
int year() const noexcept
year getter
Definition: DateTime/DateTime.hpp:134
void setSecond(int second)
second setter
Definition: DateTime/DateTime.hpp:291
static constexpr int MAX_DAY
Definition: DateTime/DateTime.hpp:54
int minute() const noexcept
minute getter
Definition: DateTime/DateTime.hpp:250
DateTime(const std::string &timestamp)
Definition: DateTime/DateTime.hpp:99
void setDay(int day)
day setter
Definition: DateTime/DateTime.hpp:201
double fractionalSecond() const noexcept
fractionalSecond getter
Definition: DateTime/DateTime.hpp:310
void setMonth(int month)
month setter
Definition: DateTime/DateTime.hpp:171
static TimePoint strToTimepoint(const std::string &timestamp)
Converts the struct to an iso string.
Definition: DateTime/DateTime.hpp:418
std::string toStr() const
Converts the struct to an iso string.
Definition: DateTime/DateTime.hpp:362
static constexpr int MAX_SECOND
Definition: DateTime/DateTime.hpp:57
static constexpr int MAX_MONTH
Definition: DateTime/DateTime.hpp:53
void setMinute(int minute)
minute setter
Definition: DateTime/DateTime.hpp:261
int month() const noexcept
month getter
Definition: DateTime/DateTime.hpp:160
int day() const noexcept
day getter
Definition: DateTime/DateTime.hpp:190
static DateTime now() noexcept
Factory static method for returning a DateTime object cooresponding to the system clock now.
Definition: DateTime/DateTime.hpp:407
DateTime(const TimePoint &tp)
Definition: DateTime/DateTime.hpp:71
void setYear(int year)
year setter
Definition: DateTime/DateTime.hpp:145
Definition: Cartesian.hpp:40
bool operator==(const DateTime &lhs, const DateTime &rhs) noexcept
Equality operator for DateTime.
Definition: DateTime/DateTime.hpp:473
bool operator>=(const std::complex< T > &lhs, const std::complex< T > &rhs) noexcept
Definition: StdComplexOperators.hpp:98
Duration operator-(const DateTime &lhs, const DateTime &rhs) noexcept
Subtraction operator.
Definition: DateTime/DateTime.hpp:551
bool operator>(const std::complex< T > &lhs, const std::complex< T > &rhs) noexcept
Definition: StdComplexOperators.hpp:84
std::chrono::nanoseconds Duration
Duration Type.
Definition: Clock.hpp:16
bool operator!=(const DateTime &lhs, const DateTime &rhs) noexcept
Non Equality operator for DateTime.
Definition: DateTime/DateTime.hpp:486
bool operator<(const std::complex< T > &lhs, const std::complex< T > &rhs) noexcept
Definition: StdComplexOperators.hpp:46
std::ostream & operator<<(std::ostream &os, Duration duration)
Output stream operator for the Duration type.
Definition: Clock.hpp:30
bool operator<=(const std::complex< T > &lhs, const std::complex< T > &rhs) noexcept
Definition: StdComplexOperators.hpp:65
std::chrono::time_point< Clock, Duration > TimePoint
TimePoint Type.
Definition: Clock.hpp:21