5.1. Получение текущей даты и времени

5.1. Получение текущей даты и времени

Проблема

Требуется получить от пользователя компьютера текущую дату и время — либо в формате локального времени, либо в формате универсального глобального времени (Coordinated Universal Time (UTC).

Григорианский календарь и високосные годы

Григорианский календарь — это наиболее широко используемый сегодня в западном мире календарь. Григорианской календарь создавался с целью исправить ошибку в юлианском календаре. Медленный процесс адаптации григорианского календаря начался в 1582 году.

Юлианский календарь говорит, что каждый четвертый год — это високосный год, но каждый сотый год — не високосный. Григорианской календарь ввел еще одно исключение — каждый 400-й год должен быть високосным.

Високосные годы предназначены для компенсации несинхронности вращения Земли вокруг Солнца и продолжительности дня. Другими словами, частное отделения продолжительности солнечного года на длительность дня — это не целое число. В результате если календарь не корректировать, то мы получим смещение сезонов, когда равноденствия и солнцестояния (которые определяют сезоны) будут все более и более рассинхронизированы с каждым новым годом.

Решение

Вызовите функцию time из заголовочного файла <ctime>, передав в качестве параметра значение 0. Результатом будет значение типа time_t. Для преобразования значения time_t в структуру tm, представляющую текущее время UTC (также известное как Greenwich Mean Time (время по Гринвичу), или GMT), используется функция gmtime, а для преобразования значения time_t в структуру tm, представляющую локальное время, используется функция localtime. Программа в примере 5.1 получает текущие дату/время, а затем преобразует их в локальное время и выводит на экран. Затем программа преобразует текущие дату/время во время/дату UTC и также выводит результат на экран.

Пример 5.1. Получение локального времени и времени UTC

#include <iostream>

#include <ctime>

#include <cstdlib>

using namespace std;

int main() {

 // Текущие дата/время используемой системы

 time_t now = time(0);

 // Преобразуем в структуру tm для локальной временной зоны

 tm* localtm = localtime(&now);

 cout << "Локальные дата и время. " << asctime(localtm) << endl;

 // Преобразуем в структуру tm для UTC

 tm* gmtm = gmtime(&now);

 if (gmtm ! = NULL) {

  cout << "Дата и время UTC: " << asctime(gmtm) << endl;

 } else {

  cerr << "Невозможно получить дату и время UTC" << endl;

  return EXIT_FAILURE;

 }

}

Обсуждение

Функция time возвращает тип time_t, который является зависящим от реализации арифметическим типом, представляющим временной период (интервал времени) с точностью до одной секунды. Наибольший интервал времени, который можно представить с помощью time_t, сохранив совместимость и переносимость кода, — это 2 147 483 648 секунд, или примерно 68 лет.

Вызов time(0) возвращает time_t, представляющее временной интервал от зависящего от реализации начала отсчета (обычно 0:00:00 1 января 1970 года) до текущего момента.

Ошибка 2038 года

Так как time_t может представлять интервалы времени длиной в 68 лет, а многие реализации для представления текущего времени в качестве начала отсчета используют 1970 год, в большинстве популярных реализаций C++ невозможно представлять даты и времена после 2038 года. Это означает, что если программисты не предпримут мер предосторожности, то в 2038 году большая часть программного обеспечения перестанет работать.

Наиболее удобное представление текущих даты и времени можно получить, преобразовав их с помощью функций localtime или gmtime в структуру tm. Структура tm содержит целочисленные поля, показанные в примере 5.2.

Пример 5.2. Содержимое структуры tm

struct tm {

 int tm_sec;   // секунды в минуте от 0 до 61 (60 и 61 для секунд координации)

 int tm_min;   // минуты в часе от 0 до 59

 int tm_hour;  // часы в сутках от 0 до 23

 int tm_mday;  // день месяца от 0 до 31

 int tm_mon;   // месяц года от 0 до 11

 int tm_year;  // год после 1900

 int tm_wday;  // дней после воскресенья

 int tm_yday;  // дней после 1-го января

 int tm_isdst; // часы летнего времени

};

При использовании функции gmtime не забудьте проверить ее возвращаемое значение. Если компьютер, на котором выполняется код, не имеет определенной локальной временной зоны (часового пояса), функция gmtime не сможет вычислить время UTC и вернет 0. Если передать 0 в функцию asctime, то результатом будет неопределенное поведение.

Функции localtime, gmtime и asctime возвращают указатели на статически размещенные в памяти объекты. Это более эффективно для библиотеки, не означает, что последующие вызовы будут изменять значение этих объектов. Код в примере 5.3 показывает, как это может привести к неожиданным эффектам.

Пример 5.3. Подводные камни использования asctime

void f() {

 char* x = asctime(localtime(time(0)));

 wait_for_15_seconds(); // выполняет длительную задачу обработки

 asctime(localtime(time(0)));

 cout << x << endl; // печатает текущее время, а не то что 15 секунд назад.

}