Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezTime is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : : #include "ezOS.hpp"
30 : :
31 : : #include <ctime>
32 : : #include <string>
33 : : #include <chrono>
34 : : #include <thread>
35 : : #include <iomanip>
36 : : #include <sstream>
37 : : #include <cstdint>
38 : : #include <functional>
39 : :
40 : : #ifndef EZ_TIME
41 : : #define EZ_TIME
42 : : #endif // EZ_TIME
43 : :
44 : : namespace ez {
45 : : namespace time {
46 : :
47 : : // convert a string ISO8601 time to epoch time
48 : 0 : inline bool iso8601ToEpoch(const std::string& vIsoDateTime, const std::string& vTimeFormat, std::time_t& vOutTime) {
49 : 0 : if (!vIsoDateTime.empty() && !vTimeFormat.empty()) {
50 : 0 : struct std::tm time = {};
51 : 0 : std::istringstream iss(vIsoDateTime);
52 : 0 : iss >> std::get_time(&time, vTimeFormat.c_str());
53 : 0 : if (!iss.fail()) {
54 : 0 : time.tm_hour = 0;
55 : 0 : time.tm_min = 0;
56 : 0 : time.tm_sec = 0;
57 : 0 : #ifdef WINDOWS_OS
58 : 0 : vOutTime = _mkgmtime(&time);
59 : 0 : #else
60 : 0 : vOutTime = timegm(&time);
61 : 0 : #endif
62 : 0 : return true;
63 : 0 : }
64 : 0 : }
65 : 0 : return false;
66 : 0 : }
67 : :
68 : : // convert a epoch time to a string ISO8601 time
69 : 0 : inline bool epochToISO8601(const std::time_t& vEpochTime, std::string& vOutTime) {
70 : 0 : auto tp = std::chrono::system_clock::from_time_t(vEpochTime);
71 : 0 : auto tt = std::chrono::system_clock::to_time_t(tp);
72 : 0 : #ifdef _MSC_VER
73 : 0 : tm _timeinfo;
74 : 0 : tm* pTimeInfo = &_timeinfo;
75 : 0 : if (localtime_s(pTimeInfo, &tt) != 0) {
76 : 0 : return false;
77 : 0 : }
78 : 0 : #else
79 : 0 : auto* pTimeInfo = std::localtime(&tt);
80 : 0 : #endif
81 : 0 : std::ostringstream oss;
82 : 0 : oss << std::put_time(pTimeInfo, "%Y-%m-%d");
83 : 0 : if (!oss.fail()) {
84 : 0 : vOutTime = oss.str();
85 : 0 : return true;
86 : 0 : }
87 : 0 : return false;
88 : 0 : }
89 : :
90 : : // TODO: TO TEST
91 : 0 : inline tm decomposeEpoch(const std::time_t& vEpochTime) {
92 : 0 : tm ret{};
93 : 0 : auto tp = std::chrono::system_clock::from_time_t(vEpochTime);
94 : 0 : auto tt = std::chrono::system_clock::to_time_t(tp);
95 : 0 : #ifdef _MSC_VER
96 : 0 : tm _timeinfo;
97 : 0 : tm* pTimeInfo = &_timeinfo;
98 : 0 : if (localtime_s(pTimeInfo, &tt) != 0) {
99 : 0 : return ret;
100 : 0 : }
101 : 0 : #else
102 : 0 : auto* pTimeInfo = std::localtime(&tt);
103 : 0 : #endif
104 : 0 : ret = *pTimeInfo;
105 : 0 : return ret;
106 : 0 : }
107 : :
108 : : // TODO: TO TEST
109 : 0 : inline std::string getCurrentDate() {
110 : 0 : auto curr_date_t = std::time(nullptr);
111 : 0 : #ifdef _MSC_VER
112 : 0 : tm _timeinfo;
113 : 0 : tm* tm_curr_date = &_timeinfo;
114 : 0 : if (localtime_s(tm_curr_date, &curr_date_t) != 0) {
115 : 0 : return {};
116 : 0 : }
117 : 0 : #else
118 : 0 : auto* tm_curr_date = std::localtime(&curr_date_t);
119 : 0 : #endif
120 : 0 : char buffer[32 + 1]{};
121 : 0 : auto s = strftime(buffer, 32, "%Y-%m-%d", tm_curr_date);
122 : 0 : buffer[s] = '\0';
123 : 0 : return std::string(buffer);
124 : 0 : }
125 : :
126 : : // TODO: TO TEST
127 : 0 : inline std::string getCurrentDate(size_t vHoursOffset) {
128 : 0 : auto curr_date_t = std::time(nullptr);
129 : 0 : #ifdef _MSC_VER
130 : 0 : tm _timeinfo;
131 : 0 : tm* tm_curr_date = &_timeinfo;
132 : 0 : if (localtime_s(tm_curr_date, &curr_date_t) != 0) {
133 : 0 : return {};
134 : 0 : }
135 : 0 : #else
136 : 0 : std::localtime(&curr_date_t);
137 : 0 : #endif
138 : 0 : std::chrono::hours offset_hours(vHoursOffset);
139 : 0 : auto curr_date = std::chrono::system_clock::from_time_t(curr_date_t);
140 : 0 : auto offset_date_t = std::chrono::system_clock::to_time_t(curr_date + offset_hours);
141 : 0 : #ifdef _MSC_VER
142 : 0 : tm* tm_offset_date = &_timeinfo;
143 : 0 : if (localtime_s(tm_offset_date, &offset_date_t) != 0) {
144 : 0 : return {};
145 : 0 : }
146 : 0 : #else
147 : 0 : auto* tm_offset_date = std::localtime(&offset_date_t);
148 : 0 : #endif
149 : 0 : char buffer[32+1]{};
150 : 0 : auto s = strftime(buffer, 32, "%Y-%m-%d", tm_offset_date);
151 : 0 : buffer[s] = '\0';
152 : 0 : return std::string(buffer);
153 : 0 : }
154 : :
155 : 1211 : inline uint64_t getTicks() {
156 : 1211 : return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
157 : 1211 : }
158 : :
159 : : // TODO: TO TEST
160 : 0 : inline float getTimeInterval() {
161 : 0 : static auto S_lastTick = getTicks();
162 : 0 : const uint64_t ticks = getTicks();
163 : 0 : static float secMult = 1.0f / 1000.0f;
164 : 0 : const float interval = (ticks - S_lastTick) * secMult;
165 : 0 : S_lastTick = ticks;
166 : 0 : return interval;
167 : 0 : }
168 : :
169 : : // TODO: TO TEST
170 : : class ActionTime {
171 : : private:
172 : : uint64_t m_LastTick = 0U;
173 : : uint64_t m_PauseTick = 0U;
174 : : uint64_t m_ResumeTick = 0U;
175 : : bool m_Play = true;
176 : :
177 : : public:
178 : 0 : ActionTime() {
179 : 0 : m_LastTick = getTicks();
180 : 0 : }
181 : :
182 : 0 : void fix() { // fixe les marqueur de temps
183 : 0 : m_LastTick = getTicks();
184 : 0 : m_PauseTick = getTicks();
185 : 0 : m_ResumeTick = getTicks();
186 : 0 : }
187 : :
188 : 0 : void fixTime(double vValue) { // fixe les marqueur de temps
189 : 0 : fix();
190 : 0 : setTime(vValue);
191 : 0 : }
192 : :
193 : 0 : void pause() {
194 : 0 : m_PauseTick = getTicks();
195 : 0 : m_Play = false;
196 : 0 : }
197 : :
198 : 0 : void resume() {
199 : 0 : m_ResumeTick = getTicks();
200 : 0 : m_LastTick += m_ResumeTick - m_PauseTick;
201 : 0 : m_Play = true;
202 : 0 : }
203 : :
204 : 0 : uint64_t get() const {
205 : 0 : return getTicks() - m_LastTick;
206 : 0 : }
207 : :
208 : 0 : double getTime() const {
209 : 0 : static double secMult = 1e-3;
210 : 0 : return (getTicks() - m_LastTick) * secMult;
211 : 0 : }
212 : :
213 : 0 : void setTime(double vValue){ // set le temps
214 : 0 : const auto v = (uint64_t)(vValue * 1000.0);
215 : 0 : m_LastTick = getTicks() - v;
216 : 0 : }
217 : :
218 : : // verifie si vMs millisecond depuis le dernier fix et donc si on peut agir
219 : : // vFix permet de fixer le temps pour la prochaine action
220 : : // on pourrait vouloir interroger sans vouloir permettre la prochaine action
221 : 0 : bool isTimeToAct(long vMs, bool vFix) {
222 : 0 : if (get() > (uint64_t)vMs) {
223 : 0 : if (vFix) {
224 : 0 : fix();
225 : 0 : }
226 : 0 : return true;
227 : 0 : }
228 : 0 : return false;
229 : 0 : }
230 : : };
231 : :
232 : : // TODO: TO TEST
233 : : //! Measure the time in microsecondes of a operation passed via lambda fucntion
234 : : //! the operation will be executed many time according to vCountOperations and averaged
235 : : template <typename TLAMBDA>
236 : : double measureOperationUs(TLAMBDA vLambda, size_t vCountOperations = 1) {
237 : : using clock = std::chrono::high_resolution_clock;
238 : : std::chrono::duration<double, std::micro> total{0};
239 : : for (size_t i = 0; i < vCountOperations; ++i) {
240 : : auto t0 = clock::now();
241 : : vLambda();
242 : : total += clock::now() - t0;
243 : : }
244 : : if (vCountOperations > 1) {
245 : : total /= static_cast<double>(vCountOperations);
246 : : }
247 : : return total.count();
248 : : }
249 : :
250 : : // will wait the condition to be true with a timeout and a step for inc time until ok or timeout
251 : 4 : static bool waitUntil(const std::function<bool(void)>& vCond, uint32_t vTimeoutMs, uint32_t vStepMs = 50) {
252 : 4 : using clock = std::chrono::steady_clock;
253 : 4 : auto start = clock::now();
254 [ + + ]: 7 : while (!vCond()) {
255 [ - + ]: 3 : if (std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start).count() >= vTimeoutMs) {
256 : 0 : return vCond(); // last chance
257 : 0 : }
258 : 3 : std::this_thread::sleep_for(std::chrono::milliseconds(vStepMs));
259 : 3 : }
260 : 4 : return true;
261 : 4 : }
262 : :
263 : : } // namespace time
264 : : } // namespace ez
|