1// LAF Base Library
2// Copyright (c) 2021-2022 Igara Studio S.A.
3// Copyright (c) 2001-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "base/time.h"
13
14#if LAF_WINDOWS
15 #include <windows.h>
16#else
17 #include <sys/time.h>
18 #if __APPLE__
19 #include <mach/mach_time.h>
20 #endif
21#endif
22
23namespace base {
24
25bool safe_localtime(const std::time_t time, std::tm* result)
26{
27#if LAF_WINDOWS
28 // localtime_s returns errno_t == 0 if there is no error
29 return (localtime_s(result, &time) != 0);
30#else
31 return (localtime_r(&time, result) != nullptr);
32#endif
33}
34
35Time current_time()
36{
37#if LAF_WINDOWS
38
39 SYSTEMTIME st;
40 GetLocalTime(&st);
41 return Time(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
42
43#else
44
45 std::time_t now = std::time(nullptr);
46 std::tm t;
47 safe_localtime(now, &t);
48 return Time(
49 t.tm_year+1900, t.tm_mon+1, t.tm_mday,
50 t.tm_hour, t.tm_min, t.tm_sec);
51
52#endif
53}
54
55tick_t current_tick()
56{
57#if LAF_WINDOWS
58 // GetTickCount() is limited to the system timer resolution (from 10
59 // to 16 milliseconds), we prefer QueryPerformanceCounter().
60 LARGE_INTEGER counter, freq;
61 if (QueryPerformanceCounter(&counter) &&
62 // TODO Call QueryPerformanceFrequency() just one time
63 QueryPerformanceFrequency(&freq)) {
64 // TODO Some precision is lost, we could return float or double
65 return counter.QuadPart * 1000 / freq.QuadPart;
66 }
67 else
68 return GetTickCount();
69#elif __APPLE__
70 static mach_timebase_info_data_t timebase = { 0, 0 };
71 if (timebase.denom == 0)
72 (void)mach_timebase_info(&timebase);
73 return tick_t(double(mach_absolute_time()) * double(timebase.numer) / double(timebase.denom) / 1.0e6);
74#else
75 // TODO use clock_gettime(CLOCK_MONOTONIC, &now); if it's possible
76 struct timeval now;
77 gettimeofday(&now, nullptr);
78 return now.tv_sec*1000 + now.tv_usec/1000;
79#endif
80}
81
82Time& Time::addSeconds(const int seconds)
83{
84 struct std::tm tm;
85 tm.tm_sec = second;
86 tm.tm_min = minute;
87 tm.tm_hour = hour;
88 tm.tm_mday = day;
89 tm.tm_mon = month-1;
90 tm.tm_year = year-1900;
91 tm.tm_wday = 0;
92 tm.tm_yday = 0;
93
94 // The value is negative if no information is available about
95 // Daylight Saving Time (DST). If we use 0 we might get one hour of
96 // difference between the input and the output.
97 tm.tm_isdst = -1;
98
99 std::time_t tt = std::mktime(&tm);
100
101 tt += seconds;
102
103 std::tm t;
104 safe_localtime(tt, &t);
105
106 year = t.tm_year+1900;
107 month = t.tm_mon+1;
108 day = t.tm_mday;
109 hour = t.tm_hour;
110 minute = t.tm_min;
111 second = t.tm_sec;
112
113 return *this;
114}
115
116bool Time::operator<(const Time& other) const
117{
118 int d = year - other.year;
119 if (d != 0) return (d < 0);
120
121 d = month - other.month;
122 if (d != 0) return (d < 0);
123
124 d = day - other.day;
125 if (d != 0) return (d < 0);
126
127 d = hour - other.hour;
128 if (d != 0) return (d < 0);
129
130 d = minute - other.minute;
131 if (d != 0) return (d < 0);
132
133 return (second < other.second);
134}
135
136} // namespace base
137