Botan 3.9.0
Crypto and TLS for C&
calendar.cpp
Go to the documentation of this file.
1/*
2* Calendar Functions
3* (C) 1999-2010,2017 Jack Lloyd
4* (C) 2015 Simon Warta (Kullo GmbH)
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/calendar.h>
10
11#include <botan/assert.h>
12#include <botan/exceptn.h>
13#include <botan/internal/target_info.h>
14#include <ctime>
15#include <iomanip>
16#include <sstream>
17
18namespace Botan {
19
20namespace {
21
22// TODO replace this with https://howardhinnant.github.io/date_algorithms.html#civil_from_days
23std::tm do_gmtime(std::time_t time_val) {
24 std::tm tm{};
25
26#if defined(BOTAN_TARGET_OS_HAS_WIN32)
27 ::gmtime_s(&tm, &time_val); // Windows
28#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
29 if(::gmtime_r(&time_val, &tm) == nullptr) {
30 throw Encoding_Error("do_gmtime could not convert");
31 }
32#else
33 std::tm* tm_p = std::gmtime(&time_val);
34 if(tm_p == nullptr) {
35 throw Encoding_Error("do_gmtime could not convert");
36 }
37 tm = *tm_p;
38#endif
39
40 return tm;
41}
42
43/*
44Portable replacement for timegm, _mkgmtime, etc
45
46Algorithm due to Howard Hinnant
47
48See https://howardhinnant.github.io/date_algorithms.html#days_from_civil
49for details and explaination. The code is slightly simplified by our assumption
50that the date is at least 1970, which is sufficient for our purposes.
51*/
52uint64_t days_since_epoch(uint32_t year, uint32_t month, uint32_t day) {
53 BOTAN_ARG_CHECK(year >= 1970, "Years before 1970 not supported");
54
55 if(month <= 2) {
56 year -= 1;
57 }
58 const uint32_t era = year / 400;
59 const uint32_t yoe = year - era * 400; // [0, 399]
60 const uint32_t doy = (153 * (month + (month > 2 ? -3 : 9)) + 2) / 5 + day - 1; // [0, 365]
61 const uint32_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
62 return era * 146097 + doe - 719468;
63}
64
65} // namespace
66
68 return (days_since_epoch(year(), month(), day()) * 86400) + (hour() * 60 * 60) + (minutes() * 60) + seconds();
69}
70
71std::chrono::system_clock::time_point calendar_point::to_std_timepoint() const {
72 const uint64_t seconds_64 = this->seconds_since_epoch();
73 const time_t seconds_time_t = static_cast<time_t>(seconds_64);
74
75 if(seconds_64 - seconds_time_t != 0) {
76 throw Invalid_Argument("calendar_point::to_std_timepoint time_t overflow");
77 }
78
79 return std::chrono::system_clock::from_time_t(seconds_time_t);
80}
81
82std::string calendar_point::to_string() const {
83 // desired format: <YYYY>-<MM>-<dd>T<HH>:<mm>:<ss>
84 std::stringstream output;
85 output << std::setfill('0') << std::setw(4) << year() << "-" << std::setw(2) << month() << "-" << std::setw(2)
86 << day() << "T" << std::setw(2) << hour() << ":" << std::setw(2) << minutes() << ":" << std::setw(2)
87 << seconds();
88 return output.str();
89}
90
91calendar_point::calendar_point(const std::chrono::system_clock::time_point& time_point) {
92 std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point));
93
94 m_year = tm.tm_year + 1900;
95 m_month = tm.tm_mon + 1;
96 m_day = tm.tm_mday;
97 m_hour = tm.tm_hour;
98 m_minutes = tm.tm_min;
99 m_seconds = tm.tm_sec;
100}
101
102} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
uint32_t hour() const
Definition calendar.h:33
uint32_t seconds() const
Definition calendar.h:41
uint32_t day() const
Definition calendar.h:30
uint64_t seconds_since_epoch() const
Definition calendar.cpp:67
std::string to_string() const
Definition calendar.cpp:82
std::chrono::system_clock::time_point to_std_timepoint() const
Definition calendar.cpp:71
calendar_point(uint32_t y, uint32_t mon, uint32_t d, uint32_t h, uint32_t min, uint32_t sec)
Definition calendar.h:52
uint32_t minutes() const
Definition calendar.h:36
uint32_t month() const
Definition calendar.h:27
uint32_t year() const
Definition calendar.h:24