, POSIX определяет, что оно представляет время в секундах. Поэтому это предположение является обычным и переносимым. Например, чтобы посмотреть, что значение времени представляет отметку в прошлом шесть месяцев назад или позже, можно использовать код, подобный этому:
/* Для краткости проверка ошибок опущена */
time_t now, then, some_time;
time(&now); /* Получить текущее время */
then = now - (6L * 31 * 24 * 60 * 60); /* Примерно 6 месяцев назад */
/* ...установить какое-нибудь время, например, через stat... */
if (some_time < then)
/* более 6 месяцев назад */
else
/* менее 6 месяцев назад */
Однако, поскольку переносимый код может потребоваться запустить на не-POSIX системах, существует функция
difftime
для вычисления разницы между двумя значениями времени. Тот же самый тест с использованием
/* ...установить какое-нибудь время, например, через stat... */
if (difftime(now, some_time) >= six_months)
/* более 6 месяцев назад */
else
/* менее 6 месяцев назад */
Возвращаемым типом
difftime
является
double
, поскольку
time_t
может также содержать доли секунд. На системах POSIX он всегда представляет целые секунды.
В обоих предыдущих примерах обратите внимание на использование типизированных констант, чтобы форсировать выполнение вычислений с нужным математическим типом:
6L
в первом случае для целых
long
, 6.0 во втором случае для чисел с плавающей точкой
6.1.2. Разложение времени:
gmtime
и
localtime
На практике форма представления даты и времени в виде «секунд с начала эпохи» не является очень удобной, кроме очень простых сравнений. Самостоятельное вычисление компонентов времени, таких, как месяц, день, год и т.д., подвержено ошибкам, поскольку необходимо принять во внимание местный часовой пояс (возможно, с учетом перехода на летнее время), правильно вычислить високосные годы и пр. К счастью, две стандартные процедуры делают за вас эту работу:
#include <time.h> /* ISO С */
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
gmtime
возвращает указатель на
struct tm
, которая представляет время UTC.
localtime
возвращает указатель на
struct tm
, представляющий местное время, т.е. в расчет берутся текущий часовой пояс и переход на летнее время. На самом деле это «время для настенных часов», дата и время, которые были бы отображены на настенных или
ручных часах. (Как это работает, обсуждается далее в разделе 6.1.5 «Получение сведений о часовом поясе».)
Обе функции возвращают указатель на
struct tm
, которая выглядит следующим образом:
struct tm {
int tm_sec; /* секунды */
int tm_min; /* минуты */
int tm_hour; /* часы */
int tm_mday; /* день месяца */
int tm_mon; /* месяц */
int tm_year; /* год */
int tm_wday; /* день недели */
int tm_yday; /* день в году */
int tm_isdst; /* летнее время */
};
struct tm
называют разложенным временем (broken-down time), поскольку значение
time_t
«разложено» на свои составные части. Составные части, их диапазоны и значения показаны в табл. 6.1.
Таблица 6.1. Поля структуры
tm
Член
Диапазон
Значение
tm_sec
0–60
Секунда минуты. Секунда 60 предусматривает пропущенные (leap) секунды. (В C89 был диапазон 0–61.)
tm_min
0–59
Минута часа.
tm_hour
0–23
Час дня
tm_mday
1–31
День месяца
tm_mon
0–11
Месяц года
tm_year
0–N
Год, начиная с 1900 г.
tm_wday
0–6
День недели, воскресенье = 0
tm_yday
0–365
День года, 1 января = 0.
tm_isdst
<0, 0, >0
Флаг летнего времени.
Стандарт ISO С представляет большинство этих значений как «
x
после
y
». Например,
tm_sec
является числом «секунд после минуты»,
tm_mon
«месяцев после января»,
tm_wday
«дней недели после воскресенья» и т.д. Это помогает понять, почему все значения начинаются с 0. (Единственным исключением, достаточно логичным, является
tm_mday
, день месяца, имеющий диапазон 1–31.) Конечно, отсчет их с нуля также практичен; поскольку массивы С отсчитываются с нуля, использование этих значений в качестве индексов тривиально: