Привет!
Следующий код должен вывести текущее время в формате UTC и местное время соответственно:
#pragma (disable : 4996)
#include <ctime>
using namespace std;
int main()
{
tm* p_current_tm_0 = gmtime(¤t_time);
tm* p_current_tm_ = localtime(¤t_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_;
}
Однако, когда я запускаю программу, на выходе дважды повторяется местное время.
Я не понимаю, почему это так.
возможно, ваше местное время — UTC. Но если нет, системе необходимо сообщить местный часовой пояс. Попробуйте вызвать setlocale(LC_ALL, NULL); выяснить
@PaulMcKenzie Приношу извинения, я отредактировал вопрос по вашему запросу.
@gbjbaanb Мое местное время не UTC, но проблема оказалась в том, что возвращаемые значения вызовов gmtime
и localtime
хранятся в одном и том же адресе памяти, что приводит к перезаписи (см. ответ ниже). Спасибо за помощь :)
как указано в других ответах, вы используете один и тот же буфер tm
для вызовов gmtime
и localtime
, а также asctime
возвращает статическую строку символов. Проблема в том, что эта функция не является потокобезопасной. Вместо этого вы можете рассмотреть strftime
, который является потокобезопасным.
@Джин отметил. Спасибо :)
Проблема здесь в том, что gmtime
и localtime
имеют один глобальный struct tm
и возвращают на него указатель. Таким образом, вызов localtime
перезаписывает структуру.
Вместо этого попробуйте это, чтобы получить копию структуры:
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
time_t current_time = time(NULL);
tm p_current_tm_0 = * gmtime(¤t_time);
tm p_current_tm_ = * localtime(¤t_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_;
}
(Да, имена переменных больше не точны, поскольку они не являются указателями.)
Альтернативно измените порядок:
tm * p_current_tm_0 = gmtime(¤t_time);
char* current_tm_0 = asctime(p_current_tm_0);
cout << "Current UTC date and time: " << current_tm_0;
tm * p_current_tm_ = localtime(¤t_time);
char* current_tm_ = asctime(p_current_tm_);
cout << "Current local date and time: " << current_tm_;
Кажется, в этом была проблема. Спасибо :)
Это немного сложно. Эти функции древние. И пара gmtime()/localtime()
, и asctime()
используют статическую память. Оба повторно используют существующую память для последующих вызовов, перезаписывая результат предыдущих вызовов! Ваши (кстати, плохо названные) указатели p_current_tm_0
и p_current_tm_
относятся к одной и той же памяти! То же самое делают указатели на символьные строки current_tm_0
и current_tm_
: ваши указатели на символы всегда относятся к одному и тому же тексту. Вот тестовая программа:
#define _CRT_SECURE_NO_WARNINGS // visual C peculiarity
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
time_t current_time;
time(¤t_time);
tm* p_current_tm_0 = gmtime(¤t_time);
tm* p_current_tm_ = localtime(¤t_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";
}
Результат:
Current UTC date and time: Sun Jun 16 20:26:20 2024
Current local date and time: Sun Jun 16 20:26:20 2024
gmt time struct mem: 000001DCF4B8F920
local time struct mem: 000001DCF4B8F920
UTC date and time string: 000001DCF4B8FF20
local date and time: 000001DCF4B8FF20
Как видите, как и вы, я получаю ту же «ошибку». Но понятно почему: обе функции используют одну и ту же память как для преобразования секунд с начала эпохи в структурированное значение времени, так и для форматирования его в виде текста! Второй вызов (localtime()
) просто перезаписывает первый вызов, получивший время UTC, а сверху второй вызов asctime()
перезаписывает текст, созданный первым.
Решение состоит в том, чтобы либо скопировать эту информацию куда-нибудь, либо использовать ее до того, как она будет перезаписана, что я и делаю здесь:
#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;
}
Я не присваиваю указатели, возвращаемые функциями, когда вызываю их второй раз! Я знаю, где они это напишут...
Дело в том, что раньше многопоточность не была чем-то особенным. (Подобная статическая память, которая используется повторно, не является потокобезопасной.) Авторы библиотек в 1970-х годах считали, что пользователю легко не обременять их, заставляя передавать указатель буфера или заставляя их удалять возвращенную память. (что было бы необходимо, если бы функции распределяли его динамически).
Кстати, передача указателя на буфер сразу же подняла бы вопрос, сколько памяти там доступно, что потребовало бы дополнительного параметра. На самом деле память ограничена, но ее объем неизвестен; крайние случаи могут привести к записи за пределами допустимого диапазона. Учитывая мудрость 45 лет, прошедших с момента создания функции, можно было бы выбрать другой дизайн. В C++ 23 они окончательно объявлены устаревшими, если верить cppreference.
Спасибо за этот довольно информативный ответ :) Я следую учебнику, и репетитор использует некоторые из этих функций (учебник обучает основам программирования с использованием C++, а не самого C++, поэтому репетитор не вдается глубоко в детали)
Однако когда я запускаю программу - в опубликованном вами коде нет программы. Нет
main
, нет объявления и настройкиcurrent_time
и т. д. Другими словами, опубликуйте минимальный воспроизводимый пример.