Quantcast
Channel: User Peter - Reinstate Monica - Stack Overflow
Viewing all articles
Browse latest Browse all 223

Answer by Peter - Reinstate Monica for std :: gmtime does not return UTC time

$
0
0

This is a bit tricky. These functions are ancient. Both the gmtime()/localtime() pair as well as asctime()use static memory. Both re-use existing memory for subsequent calls, overwriting the result of earlier calls! Your (badly named, btw) p_current_tm_0 and p_current_tm_ pointers refer to the same memory! So do the character string pointers current_tm_0 and current_tm_: Your char pointers always refer to the same text. Here is a test program:

#define _CRT_SECURE_NO_WARNINGS // visual C peculiarity#include <iostream>#include <ctime>using namespace std;int main(){    time_t current_time;    time(&current_time);    tm* p_current_tm_0 = gmtime(&current_time);    tm* p_current_tm_ = localtime(&current_time);    char* current_tm_0 = asctime(p_current_tm_0);    cout << "Current UTC date and time: " << current_tm_0;    char* current_tm_ = asctime(p_current_tm_);    cout << "Current local date and time: " << current_tm_;    cout << "gmt time struct mem:   " << (void*)p_current_tm_0 << "\n";    cout << "local time struct mem: " << (void*)p_current_tm_ <<  "\n";    cout << "\n";    cout << "UTC date and time string: " << (void*)current_tm_0 << "\n";    cout << "local date and time:      " << (void*)current_tm_  << "\n";    cout << "\n";}

The output is:

Current UTC date and time: Sun Jun 16 20:26:20 2024Current local date and time: Sun Jun 16 20:26:20 2024gmt time struct mem:   000001DCF4B8F920local time struct mem: 000001DCF4B8F920UTC date and time string: 000001DCF4B8FF20local date and time:      000001DCF4B8FF20

As you see, like you, I get the same "error". But it is clear why: Both functions use the same memory for both transforming the seconds since epoch to the structured time value, and for formatting that as text! The second call (localtime()) simply overwrites the first one that got UTC time, and on top the second asctime() call overwrites the text produced by the first.

The solution is to either copy that information somewhere or use it before it gets overwritten, which I do here:

#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <ctime>#include <cstring>using namespace std;int main(){    time_t seconds_since_1970;    time(&seconds_since_1970);    tm* ptr_to_static_tm_memory = gmtime(&seconds_since_1970);    char* ptr_to_static_time_text = asctime(ptr_to_static_tm_memory);    cout << "Current UTC date and time string: " << ptr_to_static_time_text;    // Note: No assignment necessary, function uses its built-in static memory!!    localtime(&seconds_since_1970);    // Note: No assignment necessary, function uses its built-in static memory!!    asctime(ptr_to_static_tm_memory);    cout << "Current local date and time:      " << ptr_to_static_time_text;}

I do not assign the pointers returned by the functions when I call them the second time! I know where they are going to write that ...

The background is that back in the day, multi-threading was not a thing. (Static memory like this which is re-used is not thread safe.) The library writers in the 1970s thought it is easy on the user to not burden them by forcing them to pass a buffer pointer, or forcing them to delete the returned memory (which would be necessary if the functions allocated it dynamically).

Incidentally, passing a buffer pointer would immediately raise the question how much memory is available there, which would have necessitated an extra parameter. As it is, the memory is limited but its amount is unknown; edge cases may cause out-of-bounds writes. With the wisdom of the 45 years or so which have passed since the functions' inception one would choose a different design. In C++ 23, they are finally deprecated, if we can believe cppreference.


Viewing all articles
Browse latest Browse all 223

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>