The Battle for Wesnoth  1.15.3+dev
time.cpp
Go to the documentation of this file.
1 //
2 // M A R I A D B + +
3 //
4 // Copyright Sylvain Rochette Langlois 2013,
5 // Frantisek Boranek 2015,
6 // The ViaDuck Project 2016 - 2020.
7 // Distributed under the Boost Software License, Version 1.0.
8 // (See accompanying file LICENSE or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #include <mysql.h>
12 #include <sstream>
13 #include <mariadb++/exceptions.hpp>
14 #include <mariadb++/date_time.hpp>
15 #include <mariadb++/time.hpp>
17 #include <iomanip>
18 #include <chrono>
19 #include "private.hpp"
20 
21 #define MS_PER_SEC 1000
22 #define MS_PER_MIN (MS_PER_SEC * 60)
23 #define MS_PER_HOUR (MS_PER_MIN * 60)
24 #define MS_PER_DAY (MS_PER_HOUR * 24)
25 
26 mariadb::time::time(u8 hour, u8 minute, u8 second, u16 millisecond) {
27  set(hour, minute, second, millisecond);
28 }
29 
30 mariadb::time::time(const time& t) { set(t.hour(), t.minute(), t.second(), t.millisecond()); }
31 
32 mariadb::time::time(const tm& t) { set(t.tm_hour, t.tm_min, t.tm_sec, 0); }
33 
34 mariadb::time::time(const time_t& t) {
35  tm ts;
36  localtime_safe(&ts, &t);
37 
38  set(ts.tm_hour, ts.tm_min, ts.tm_sec, 0);
39 }
40 
41 mariadb::time::time(const MYSQL_TIME& t) { set(t.hour, t.minute, t.second, t.second_part / 1000); }
42 
44 
45 int mariadb::time::compare(const time& t) const {
46  if (hour() < t.hour()) return -1;
47 
48  if (hour() > t.hour()) return 1;
49 
50  if (minute() < t.minute()) return -1;
51 
52  if (minute() > t.minute()) return 1;
53 
54  if (second() < t.second()) return -1;
55 
56  if (second() > t.second()) return 1;
57 
58  if (millisecond() < t.millisecond()) return -1;
59 
60  return millisecond() == t.millisecond() ? 0 : 1;
61 }
62 
64  set(t.hour(), t.minute(), t.second(), t.millisecond());
65  return *this;
66 }
67 
68 bool mariadb::time::operator==(const time& t) const { return compare(t) == 0; }
69 
70 bool mariadb::time::operator!=(const time& t) const { return compare(t) != 0; }
71 
72 bool mariadb::time::operator<(const time& t) const { return compare(t) < 0; }
73 
74 bool mariadb::time::operator<=(const time& t) const { return compare(t) <= 0; }
75 
76 bool mariadb::time::operator>(const time& t) const { return compare(t) > 0; }
77 
78 bool mariadb::time::operator>=(const time& t) const { return compare(t) >= 0; }
79 
81  m_hour = hour;
82  m_minute = minute;
83  m_second = second;
85  return true;
86 }
87 
89 
91  if (hour > 23)
93 
94  m_hour = hour;
95 
96  return m_hour;
97 }
98 
100 
102  if (minute > 59)
104 
105  m_minute = minute;
106 
107  return m_minute;
108 }
109 
111 
113  if (second > 61)
115 
116  m_second = second;
117 
118  return m_second;
119 }
120 
122 
124  if (millisecond > 999)
125  MARIADB_ERROR_THROW_TIME(hour(), minute(), second(), millisecond);
126 
128 
129  return m_millisecond;
130 }
131 
133  mariadb::time tmp = *this;
134 
135  if (hours == 0) return tmp;
136 
137  // hour overflow does not matter, as we dont care about days
138  hours = (hours + hour() + 24) % 24;
139  tmp.hour(hours);
140  return tmp;
141 }
142 
144  mariadb::time tmp = *this;
145 
146  if (minutes == 0) return tmp;
147 
148  s32 hours = minutes / 60;
149  minutes = (minutes % 60) + minute();
150 
151  if (minutes >= 60)
152  ++hours;
153  else if (minutes < 0)
154  --hours;
155 
156  if (hours != 0) tmp = tmp.add_hours(hours);
157 
158  tmp.minute((minutes + 60) % 60);
159  return tmp;
160 }
161 
163  mariadb::time tmp = *this;
164 
165  if (seconds == 0) return tmp;
166 
167  s32 minutes = seconds / 60;
168  seconds = (seconds % 60) + second();
169 
170  if (seconds >= 60)
171  ++minutes;
172  else if (seconds < 0)
173  --minutes;
174 
175  if (minutes != 0) tmp = tmp.add_minutes(minutes);
176 
177  tmp.second((seconds + 60) % 60);
178  return tmp;
179 }
180 
182  mariadb::time tmp = *this;
183 
184  if (milliseconds == 0) return tmp;
185 
186  s32 seconds = milliseconds / 1000;
187  milliseconds = (milliseconds % 1000) + millisecond();
188 
189  if (milliseconds > 999)
190  ++seconds;
191  else if (milliseconds < 0)
192  --seconds;
193 
194  if (seconds != 0) tmp = tmp.add_seconds(seconds);
195 
196  tmp.millisecond((milliseconds + 1000) % 1000);
197  return tmp;
198 }
199 
201  // copy and negate timespan
202  time_span tmp = dur;
203  tmp.negative(!dur.negative());
204 
205  // add negated
206  return add(tmp);
207 }
208 
210  // negate if needed
211  s32 negative = dur.negative() ? -1 : 1;
212  time tmp = *this;
213 
214  tmp.add_hours(negative * dur.hours());
215  tmp.add_minutes(negative * dur.minutes());
216  tmp.add_seconds(negative * dur.seconds());
217  tmp.add_milliseconds(negative * dur.milliseconds());
218  return tmp;
219 }
220 
222  // equal
223  if (t == *this) return time_span(0, 0, 0, 0, 0);
224 
225  // recursive call with negation
226  if (t > *this) {
227  time_span dur = t.time_between(*this);
228  dur.negative(true);
229  return dur;
230  }
231 
232  // calculate the ms representation of both
233  s64 ms =
234  (hour() * MS_PER_HOUR) + (minute() * MS_PER_MIN) + (second() * MS_PER_SEC) + millisecond();
235  s64 t_ms = (t.hour() * MS_PER_HOUR) + (t.minute() * MS_PER_MIN) + (t.second() * MS_PER_SEC) +
236  t.millisecond();
237  s64 total_ms = 0;
238 
239  // subtract the lesser from greater // TODO: is this case ever reached since we have recusive
240  // call on t > this?
241  if (t_ms > ms)
242  total_ms = MS_PER_DAY - (t_ms - ms);
243  else
244  total_ms = ms - t_ms;
245 
246  u32 hours = static_cast<u32>(total_ms / MS_PER_HOUR);
247  total_ms = total_ms % MS_PER_HOUR;
248 
249  u32 minutes = static_cast<u32>(total_ms / MS_PER_MIN);
250  total_ms = total_ms % MS_PER_MIN;
251 
252  u32 seconds = static_cast<u32>(total_ms / MS_PER_SEC);
253  total_ms = total_ms % MS_PER_SEC;
254 
255  return time_span(0, hours, minutes, seconds, static_cast<u32>(total_ms), false);
256 }
257 
258 time_t mariadb::time::mktime() const {
259  tm time_struct;
260 
261  time_struct.tm_year = 1900;
262  time_struct.tm_mon = 0;
263  time_struct.tm_mday = 1;
264  time_struct.tm_hour = hour();
265  time_struct.tm_min = minute();
266  time_struct.tm_sec = second();
267 
268  return ::mktime(&time_struct);
269 }
270 
271 MYSQL_TIME mariadb::time::mysql_time() const {
272  MYSQL_TIME t;
273 
274  t.year = 0;
275  t.month = 0;
276  t.day = 0;
277  t.hour = hour();
278  t.minute = minute();
279  t.second = second();
280  t.second_part = millisecond() * 1000u;
281  t.neg = false;
282  t.time_type = MYSQL_TIMESTAMP_TIME;
283  return t;
284 }
285 
286 double mariadb::time::diff_time(const time& t) const {
287  time_t time_val = mktime();
288  time_t t_time_val = t.mktime();
289 
290  return ::difftime(time_val, t_time_val);
291 }
292 
294  return time::valid_time(hour(), minute(), second(), millisecond());
295 }
296 
298  // seconds go up to 61 to allow for leap seconds
299  return hour < 24 && minute < 60 && second <= 61 && millisecond < 1000;
300 }
301 
303  using namespace std::chrono;
304  auto now = system_clock::now();
305 
306  time_t local_time = system_clock::to_time_t(now);
307  tm ts;
308  localtime_safe(&ts, &local_time);
309 
310  auto millis = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
311  return mariadb::time(ts).add_milliseconds(static_cast<s32>(millis));
312 }
313 
315  using namespace std::chrono;
316  auto now = system_clock::now();
317 
318  time_t utc_time = system_clock::to_time_t(now);
319  tm ts;
320  gmtime_safe(&ts, &utc_time);
321 
322  auto millis = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
323  return mariadb::time(ts).add_milliseconds(static_cast<s32>(millis));
324 }
325 
327  std::stringstream stream(t);
328 
329  u8 h, m, s;
330  u16 s_h = 0, s_m = 0, s_s = 0, s_ms = 0;
331  char delim;
332 
333  // read formatted hours, check overflow before cast
334  if (stream >> s_h && s_h < 24) {
335  h = static_cast<u8>(s_h);
336  if (stream.eof()) return set(h, 0, 0, 0);
337 
338  // read formatted minutes, check overflow before cast
339  if (stream >> delim && stream >> s_m && s_m < 60) {
340  m = static_cast<u8>(s_m);
341  if (stream.eof()) return set(h, m, 0, 0);
342 
343  // read formatted seconds, check overflow before cast
344  if (stream >> delim && stream >> s_s && s_s < 62) {
345  s = static_cast<u8>(s_s);
346  if (stream.eof()) return set(h, m, s, 0);
347 
348  // read formatted millis
349  if (stream >> delim && stream >> s_ms) return set(h, m, s, s_ms);
350  }
351  }
352  }
353 
354  throw std::invalid_argument("invalid time format");
355 }
356 
357 const std::string mariadb::time::str_time(bool with_millisecond) const {
358  std::stringstream stream;
359  stream.fill('0');
360 
361  /*
362  * Note: the magic unary + forces conversion of unsigned char (u8) to a numeric printing type,
363  * otherwise it will
364  * be printed as char
365  */
366  stream << std::setw(2) << +hour() << ":" << std::setw(2) << +minute() << ":" << std::setw(2)
367  << +second();
368 
369  if (with_millisecond) stream << "." << std::setw(3) << millisecond();
370 
371  return stream.str();
372 }
373 
374 std::ostream& mariadb::operator<<(std::ostream& os, const time& t) {
375  os << t.str_time(true);
376  return os;
377 }
bool operator<(const time &t) const
Checks if this instance is lesser than t.
Definition: time.cpp:72
u16 millisecond() const
Get the current millisecond 0-999.
Definition: time.cpp:121
signed int s32
Definition: types.hpp:25
Class representing SQL time.
Definition: time.hpp:23
virtual bool is_valid() const
Indicates whether this time is considered valid.
Definition: time.cpp:293
u8 second() const
Get the current second 0-61 (leap second possible)
Definition: time.cpp:110
time & operator=(const time &t)
Assigns a value to this instance.
Definition: time.cpp:63
time subtract(const time_span &dur) const
Subtracts the given timespan from the current time.
Definition: time.cpp:200
u8 minute() const
Get the current minute 0-59.
Definition: time.cpp:99
u8 seconds() const
Get number of seconds.
Definition: time_span.cpp:102
int compare(const time &t) const
Compare this instance to given instance.
Definition: time.cpp:45
#define h
double diff_time(const time &t) const
Calculates the time difference using ::difftime.
Definition: time.cpp:286
bool operator<=(const time &t) const
Checks if this instance is lesser or equal to t.
Definition: time.cpp:74
time add_milliseconds(s32 milliseconds) const
Adds a certain amount of milliseconds to the current time.
Definition: time.cpp:181
std::ostream & operator<<(std::ostream &os, const date_time &ddt)
Definition: date_time.cpp:587
time(u8 hour=0, u8 minute=0, u8 second=0, u16 millisecond=0)
Construct time using given values.
Definition: time.cpp:26
u16 milliseconds() const
Get number of milliseconds.
Definition: time_span.cpp:110
const std::string str_time(bool with_millisecond=false) const
Converts the time to a string with the format hh:mm:ss[.nnn].
Definition: time.cpp:357
bool operator>(const time &t) const
Checks if this instance is greater than t.
Definition: time.cpp:76
time add_minutes(s32 minutes) const
Adds a certain amount of minutes to the current time.
Definition: time.cpp:143
u8 hour() const
Get the current hour 0-23.
Definition: time.cpp:88
bool operator!=(const time &t) const
Checks for unequality.
Definition: time.cpp:70
bool operator>=(const time &t) const
Checks if this instance is greater or equal to t.
Definition: time.cpp:78
unsigned char u8
Definition: types.hpp:20
unsigned short u16
Definition: types.hpp:21
signed long long s64
Definition: types.hpp:35
#define MS_PER_HOUR
Definition: time.cpp:23
int gmtime_safe(struct tm *_tm, const time_t *_time)
Definition: private.hpp:27
time add_seconds(s32 seconds) const
Adds a certain amount of seconds to the current time.
Definition: time.cpp:162
time add(const time_span &dur) const
Adds the given timespan to the current time.
Definition: time.cpp:209
#define MS_PER_DAY
Definition: time.cpp:24
static map_location::DIRECTION s
static time now()
Uses time.h to determine the current time in the local timezone.
Definition: time.cpp:302
time add_hours(s32 hours) const
Adds a certain amount of hours to the current time.
Definition: time.cpp:132
u16 m_millisecond
Definition: time.hpp:310
static time now_utc()
Uses time.h to determine the current time in UTC timezone.
Definition: time.cpp:314
double t
Definition: astarsearch.cpp:64
bool negative() const
Indicates whether this time_span is negative.
Definition: time_span.cpp:118
time_span time_between(const time &t) const
Calculates the timespan between the current time instance and given instance t.
Definition: time.cpp:221
u8 minutes() const
Get number of hours.
Definition: time_span.cpp:94
#define MS_PER_MIN
Definition: time.cpp:22
virtual bool set(const std::string &t)
Set the time from string The format needs to be hh[:mm][:ss][.nnn] where less digits are possible and...
Definition: time.cpp:326
#define MARIADB_ERROR_THROW_TIME(_hour, _minute, _second, _millisecond)
Definition: private.hpp:48
static bool valid_time(u8 hour, u8 minute, u8 second, u16 millisecond)
Indicates whether a given time is valid in terms of limits.
Definition: time.cpp:297
time_t mktime() const
Converts the time to time_t (time.h representation)
Definition: time.cpp:258
unsigned int u32
Definition: types.hpp:22
u8 hours() const
Get number of hours.
Definition: time_span.cpp:86
int localtime_safe(struct tm *_tm, const time_t *_time)
Definition: private.hpp:23
MYSQL_TIME mysql_time() const
Converts the time to MySQL time representation.
Definition: time.cpp:271
#define MS_PER_SEC
Definition: time.cpp:21
bool operator==(const time &t) const
Checks for equality.
Definition: time.cpp:68