Выбрать главу

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 секунд назад.

}

5.2. Форматирование даты/времени в виде строки

Проблема

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

Решение

Используйте шаблон класса time_put из заголовочного файла <locale>, как показано в примере 5.4.

Пример 5.4. Форматирование строки даты/времени

#include <iostream>

#include <cstdlib>

#include <ctime>

#include <cstring>

#include <string>

#include <stdexcept>

#include <iterator>

#include <sstream>

using namespace std;

ostream& formatDateTime(ostream& out, const tm& t, const char* fmt) {

 const time_put<char>& dateWriter = use_facet<time_put<char> >(out.getloc());

 int n = strlen(fmt);

 if (dateWriter.put(out, out, ' ', &t, fmt, fmt + n).failed()) {

  throw runtime_error("невозможно отформатировать дату и время");

 }

 return out;

}

string dateTimeToString(const tm& t, const char* format) {

 stringstream s;

 formatDateTime(s, t.format);

 return s.str();

}

tm now() {

 time_t now = time(0);

 return *localtime(&now);

}

int main() {

 try {

  string s = dateTimeToString(now(), "%A %B, %d %Y %I:%M%p");

  cout << s << endl;

  s = dateTimeToString(now(), "%Y-%m-%d %H:%M:%S);

  cout << s << endl;

 } catch(...) {

  cerr << "невозможно отформатировать дату и время" << endl;

  return EXIT FAILURE.

 }

 return EXIT_SUCCESS;

}

Вывод программы из примера 5.4 будет содержать нечто подобное следующему, в зависимости от локальных настроек.

Sunday July, 24 2005 05:48PM 2005-07-24 17:48:11

Обсуждение

Метод put из time_put использует спецификатор форматирования строки, аналогичный строке формата функции С printf. Символы строки формата выводятся в выходной буфер по мере их появления при условии, что им не предшествует символ %. Символ, перед которым стоит %, — это спецификатор формата, который имеет специальное значение, приведенное в табл. 5.1. Спецификаторы формата также поддерживают модификаторы, такие как целое число, указывающее длину поля, как в %4B.

Tабл. 5.1. Спецификаторы формата даты/времени

Спецификатор Описание
a Сокращенное название дня недели (например, Mon (пн))
A Полное название дня недели (например, Monday (понедельник))
b Сокращенное название месяца (например, Dec (дек))
B Полное название месяца (например, May (май))
c Полные дата и время
d День месяца (01-31)
H Час (00-23)
I Час (01-12)
j День года (001-366)
m Месяц (01-12)
M Минуты (00-59)
p Признак AM/PM
S Секунды, включая до двух секунд координации
U Номер недели (00-53), причем неделя 1 начинается в первое воскресенье
w День недели (0-6), где 0 — это воскресенье
W Номер недели (00-53), причем неделя 1 начинается в первый понедельник
x Дата в формате MM/DD/YY
X Время в формате HH/MM/SS и 24-часовыми часами
y Год текущего столетия (00-99)
Y Год
Z Сокращение временной зоны (часового пояса), или пустая строка, если зона неизвестна