And replace them with just hardcoded ISO8601 strings and gmtime_r.
Pointed out by @laanwj here: #12970 (comment)
And replace them with just hardcoded ISO8601 strings and gmtime_r.
Pointed out by @laanwj here: #12970 (comment)
85 | - ss << boost::posix_time::from_time_t(nTime); 86 | - return ss.str(); 87 | + char buf[256]; 88 | + struct tm time_struct; 89 | + time_t time_val = nTime; 90 | + gmtime_r(&time_val, &time_struct);
Is this portable? Afiak all of the madness is usually an abstraction of these variants.
Well at least this code doesn't need any allocations.
Why don't just use gmtime? It's more portable.
@ken2812221 gmtime is not thread safe. We either user gmtime_r, or introduce a lock around the call.
Concept ACK
A potential problem is that strftime depends on the locale, just like many other C string formatting functions, which has made us avoid them in general. From the developer notes:
- Use
std::string, avoid C string manipulation functions- Rationale: C++ string handling is marginally safer, less scope for buffer overflows and surprises with
\0characters. Also some C string manipulations tend to act differently depending on platform, or even the user locale
The imbue stuff forces using the 'C' locale, I'm afraid if we want to use C functions we'd need a C equivalent of that and that's probably just as bad.
FWIW it doesn't need full strftime support. The only datetime formats left in non-test code are ISO8601:
src/utiltime.cpp: return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
src/utiltime.cpp: return DateTimeStrFormat("%Y-%m-%d", nTime);
src/utiltime.cpp: return DateTimeStrFormat("%H:%M:%SZ", nTime);
Another potential simplification could be around that they all deal with UTC, and have UNIX epoch format as input.
Edit: so to be clear, big concept ACK on getting rid of this madness, but let's think about the replacement a bit. Maybe there's something like tinyformat.h that we can just import from somewhere...
The imbue stuff forces using the 'C' locale, I'm afraid if we want to use C functions we'd need a C equivalent of that and that's probably just as bad.
A reminder that this is where we're coming from: 3e8ac6af9a993e262d1160fb2e6e1e1f1d5d19f2
Edit: Thinking about it further - it becomes less clear to me whether the slowness is due to our own code, or due to formatting, or something else. After all, the speed seems to depend on the operating system. Maybe the slowdown (fixed by #12970) is due to barraging the kernel with "get current time" system calls. This is fairly fast on Linux - due to vdso user-space implementation of some syscalls - but not on windows or other OSes.
@laanwj Thanks, you're right that this approach ignores the reasons why the old code existed in the first place. I've replaced it with just hardcoded ISO8601 format strings... please let me know if you think this is too NIH.
Perhaps this is overkill as it may not help for performance. I remember we've had multiple horror stories in the past with this code though; I'd prefer to get rid of it.
I've replaced it with just hardcoded ISO8601 format strings... please let me know if you think this is too NIH.
No I think this is great :+1: It's very straightforward.
tACK 152701568159915828613fa131e94e21337c0c2d
utACK 152701568159915828613fa131e94e21337c0c2d
89 | - 90 | std::string FormatISO8601DateTime(int64_t nTime) { 91 | - return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); 92 | + struct tm ts; 93 | + time_t time_val = nTime; 94 | + gmtime_r(&time_val, &ts);
I'm happy that this works on windows as-is as well!
utACK 152701568159915828613fa131e94e21337c0c2d
As an fyi Windows doesn't come with gmtime_r so this PR broke the msvc build.
I'd say there's an easy enough workaround and will look into it.