-
Notifications
You must be signed in to change notification settings - Fork 272
/
time.cpp
185 lines (150 loc) · 6.52 KB
/
time.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/time.hpp"
#include <sstream>
#include <string>
#include <cstring>
#include <cmath>
#include <chrono>
#include <cassert>
#include <iomanip>
#ifdef __MACH__
#include <sys/time.h>
#endif
namespace g3 {
namespace internal {
const std::string kFractionalIdentier = "%f";
const size_t kFractionalIdentierSize = 2;
Fractional getFractional(const std::string& format_buffer, size_t pos) {
char ch = (format_buffer.size() > pos + kFractionalIdentierSize ? format_buffer.at(pos + kFractionalIdentierSize) : '\0');
Fractional type = Fractional::NanosecondDefault;
switch (ch) {
case '3': type = Fractional::Millisecond; break;
case '6': type = Fractional::Microsecond; break;
case '9': type = Fractional::Nanosecond; break;
default: type = Fractional::NanosecondDefault; break;
}
return type;
}
// Returns the fractional as a string with padded zeroes
// 1 ms --> 001
// 1 us --> 000001
// 1 ns --> 000000001
std::string to_string(const timespec& time_snapshot, Fractional fractional) {
auto ns = time_snapshot.tv_nsec;
auto zeroes = 9; // default ns
auto digitsToCut = 1; // default ns, divide by 1 makes no change
switch (fractional) {
case Fractional::Millisecond : {
zeroes = 3;
digitsToCut = 1000000;
break;
}
case Fractional::Microsecond : {
zeroes = 6;
digitsToCut = 1000;
break;
}
case Fractional::Nanosecond :
case Fractional::NanosecondDefault:
default:
zeroes = 9;
digitsToCut = 1;
}
ns /= digitsToCut;
// auto value = std::to_string(typeAdjustedValue);
// return value; // std::string(fractional_digit, '0') + value;
auto value = std::string(std::to_string(ns));
return std::string(zeroes - value.size(), '0') + value;
}
} // internal
} // g3
namespace g3 {
std::time_t systemtime_now() {
system_time_point system_now = std::chrono::system_clock::now();
return std::chrono::system_clock::to_time_t(system_now);
}
int timespec_get(struct timespec* ts/*, int base*/) {
#ifdef __MACH__
// std::timespec_get or posix clock_gettime)(...) are not
// implemented on OSX
// @return value of base if successful, else zero
struct timeval now = {};
int rv = gettimeofday(&now, nullptr);
if (-1 == rv) {
return rv;
}
// error mode. just return sec, microsecond
ts->tv_sec = now.tv_sec;
ts->tv_nsec = now.tv_usec * 1000;
return 0;
#elif(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
return timespec_get(ts, TIME_UTC);
#else
// ubuntu/gcc5 has no support for std::timespec_get(...) as of yet
return clock_gettime(CLOCK_REALTIME, ts);
#endif
}
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
// return value is SIMPLIFIED to only return a std::string
std::string put_time(const struct tm* tmb, const char* c_time_format) {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__)
std::ostringstream oss;
oss.fill('0');
// BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
oss << std::put_time(const_cast<struct tm*> (tmb), c_time_format);
return oss.str();
#else // LINUX
const size_t size = 1024;
char buffer[size]; // IMPORTANT: check now and then for when gcc will implement std::put_time.
// ... also ... This is way more buffer space then we need
auto success = std::strftime(buffer, size, c_time_format, tmb);
// In DEBUG the assert will trigger a process exit. Once inside the if-statement
// the 'always true' expression will be displayed as reason for the exit
//
// In Production mode
// the assert will do nothing but the format string will instead be returned
if (0 == success) {
assert((0 != success) && "strftime fails with illegal formatting");
return c_time_format;
}
return buffer;
#endif
}
tm localtime(const std::time_t& time) {
struct tm tm_snapshot;
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__))
localtime_s(&tm_snapshot, &time); // windsows
#else
localtime_r(&time, &tm_snapshot); // POSIX
#endif
return tm_snapshot;
}
std::string localtime_formatted(const timespec& time_snapshot, const std::string& time_format) {
auto format_buffer = time_format; // copying format string to a separate buffer
// iterating through every "%f" instance in the format string
auto identifierExtraSize = 0;
for (size_t pos = 0; (pos = format_buffer.find(g3::internal::kFractionalIdentier, pos)) != std::string::npos; pos += g3::internal::kFractionalIdentierSize + identifierExtraSize) {
// figuring out whether this is nano, micro or milli identifier
auto type = g3::internal::getFractional(format_buffer, pos);
auto value = g3::internal::to_string(time_snapshot, type);
auto padding = 0;
if (type != g3::internal::Fractional::NanosecondDefault) {
padding = 1;
}
// replacing "%f[3|6|9]" with sec fractional part value
format_buffer.replace(pos, g3::internal::kFractionalIdentier.size() + padding, value);
}
return localtime_formatted(time_snapshot.tv_sec, format_buffer);
}
std::string localtime_formatted(const std::time_t& time_snapshot, const std::string& time_format) {
std::tm t = localtime(time_snapshot); // could be const, but cannot due to VS2012 is non conformant for C++11's std::put_time (see above)
return g3::put_time(&t, time_format.c_str()); // format example: //"%Y/%m/%d %H:%M:%S");
}
} // g3