Программирование в стандарте POSIX


Преобразование данных о времени


Стандартом POSIX-2001 предусмотрено несколько способов представления данных о времени. Выше были описаны структура tm и тип time_t. Кроме того, время может записываться в виде цепочки символов. (Есть еще структуры timeval и timespec, но они в данном контексте играют подчиненную роль, лишь уточняя значения типа time_t.)

Для выполнения преобразований между разными представлениями данных о времени служат описываемые далее функции (см. также рис. 12.1).


Рис. 12.1.  Функции для выполнения преобразований между разными представлениями данных о времени.

Функции gmtime() и localtime() (см. листинг 12.8) преобразуют значения типа time_t в структуру типа tm. Соотношение между временем в секундах от начала отсчета и значениями полей структуры типа tm дается в приведенной выше формуле. Кроме того, функция localtime() учитывает данные о часовом поясе и сезонных поправках.

#include <time.h> struct tm *gmtime (const time_t *tloc); struct tm *localtime (const time_t *tloc)

Листинг 12.8. Описание функций gmtime() и localtime(). (html, txt)

Для учета данных о часовом поясе и сезонных поправках используются внешние переменные tzname, timezone, daylight, значения которых функция tzset() устанавливает по переменной окружения TZ (см. листинг 12.9).

#include <time.h> extern char *tzname[2]; extern long timezone; extern int daylight; void tzset (void);

Листинг 12.9. Описание функции tzset() и ассоциированных внешних переменных. (html, txt)

Элементам массива tzname присваиваются имена местного часового пояса в стандартном (tzname [0]) и "летнем" (tzname [1]) вариантах. Значение переменной timezone устанавливается равным разности в секундах между всемирным и местным поясным временем. Переменной daylight присваивается отличное от нуля значение, если для местного часового пояса предусмотрен переход на летнее время.

Отметим, что в общем случае значение переменой окружения TZ устроено довольно сложным образом:

Станд_поясСмещение[Лет_пояс[Смещение] [,Нач_лет[/Время],Кон_лет[/Время]]]


Здесь Станд_пояс и Лет_пояс - имена, присваиваемые элементам массива tzname [], Смещение - разность между всемирным и местным поясным временем (в виде чч[:мм[:сс]]), Нач_лет и Кон_лет, соответственно, даты начала и окончания действия летнего времени (обычно их задают в виде Mмм.н.д - месяц, неделя, день), время - время перехода (по умолчанию - два часа ночи). Можно видеть, что данных для вычисления местного времени оказывается вполне достаточно.

Функцию mktime() (см. листинг 12.10) можно считать обратной по отношению к localtime(). Она преобразует местное время, заданное в виде структуры типа tm, в значение типа time_t, т. е. в секунды от начала отсчета по всемирному времени.

#include <time.h> time_t mktime (struct tm *tmptr);

Листинг 12.10. Описание функции mktime(). (html, txt)

При входе в функцию mktime() значения полей tm_wday и tm_yday структуры tm, на которую указывает аргумент tmptr, игнорируются; при выходе они устанавливаются должным образом. Значения других полей также приводятся к стандартным для них диапазонам (при входе это условие может не выполняться).

Другим весьма мощным средством преобразования местного времени из структурного в текстовое представление является функция strftime() (см. листинг 12.11). Как и служебная программа date, она преобразует дату и время в соответствии с заданным форматом, только исходными данными служит не текущий момент времени, а структура типа tm, на которую указывает аргумент tmptr, и результат направляется не на стандартный вывод, а в буфер, заданный указателем s и длиной maxsize.



#include <time.h> size_t strftime (char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict tmptr);

Листинг 12.11. Описание функции strftime(). (html, txt)

По сравнению с date, функция strftime() содержит несколько дополнительных спецификаторов форматных преобразований. Перечислим наиболее употребительные из них.

Таблица 12.1. Спецификаторы преобразованийСпецификаторОписание
%FПредставление даты в соответствии со стандартом ISO 8601:2000: эквивалент последовательности спецификаторов %Y-%m-%d.
%R

Часы и минуты (%H:%M) в 24-часовом представлении.
%zСмещение относительно всемирного времени, представленное по стандарту ISO 8601:2000: +ччмм или -ччмм (положительные значения соответствуют часовым поясам к востоку от Гринвича).
<


Функция strftime() возвращает число байт, помещенное в буфер (без учета завершающего нулевого байта). Если буфер оказался мал, возвращается ноль.

На роль обратной по отношению к strftime() могут претендовать сразу две функции: strptime() и getdate() (см. листинг 12.12).

#include <time.h> char *strptime (const char *restrict s, const char *restrict format, struct tm *restrict tmptr); struct tm *getdate (const char *s);

Листинг 12.12. Описание функций strptime() и getdate(). (html, txt)

Функция strptime() напоминает sscanf(): она сканирует цепочку символов, на которую указывает аргумент s, в соответствии с заданным форматом, включающим описанные выше спецификаторы преобразований, а также, быть может, пробельные и обычные символы, и помещает извлеченные значения в структуру типа tm по указателю tmptr. В качестве результата возвращается указатель на первый несканированный символ или NULL в случае неудачи.

Функция getdate(), по сути аналогичная strptime(), использует для разбора входной цепочки s форматы, содержащиеся в файле, чье полное маршрутное имя задано переменной окружения DATEMSK (для интерпретации выбирается первый подходящий формат). Если дата и время специфицированы не полностью (например, задан только день недели), как исходные берутся данные о первом подходящем моменте времени, начиная с текущего. Если в формате присутствует спецификатор %Z, выходная структура инициализируется текущим временем в сканируемом часовом поясе. В противном случае применяется местное время.

С помощью внешней переменной (или макроса) getdate_err функция getdate() возвращает коды ошибок.

Приведем пример использования описанных функций преобразования данных о времени (см. листинг 12.13).

Листинг 12.13. Пример программы, использующей функции преобразования данных о времени. (html, txt)

Возможные результаты выполнения этой программы показаны в листинге 12.14.

Листинг 12.14. Возможные результаты работы программы, использующей функции преобразования данных о времени. (html, txt)

Последовательность инструкций языка C

char dtbuf []; time_t st; (void) strftime (dtbuf, sizeof (dtbuf), "%c", localtime (&st));

является стандартной для получения текущего времени в текстовом виде. (Разумеется, вместо "%c" допустим другой спецификатор преобразования.) Нужно помнить только, что функции gmtime() и localtime() возвращают указатели на статические структуры, содержимое которых, возможно, перезаписывается при каждом вызове, поэтому, если оно понадобится в дальнейшем, его следует скопировать в собственные объекты.



(void) strftime (dtbuf, sizeof (dtbuf), "%c", localtime (&st)); printf ("Текущее местное время: %s\n", dtbuf);

/* Узнаем, каким днем недели будет 01 января 2038 года */ stm.tm_year = 2038 - 1900; stm.tm_mon = 1 - 1; stm.tm_mday = 1; stm.tm_hour = 0; stm.tm_min = 0; stm.tm_sec = 0; stm.tm_isdst = -1; if ((st = mktime (&stm)) == (time_t) (-1)) { perror ("MKTIME"); } else { (void) strftime (dtbuf, sizeof (dtbuf), "%A", &stm); printf ("День недели 01 января 2038 года: %s\n", dtbuf); printf ("Число секунд от начала отсчета в начале 2038 года (шест.): %x\n", (unsigned int) st); }

/* Узнаем, когда наступит переполнение значений типа time_t, */ /* представленных как 32-разрядное целое со знаком */ st = (time_t) 0x7fffffff; (void) strftime (dtbuf, sizeof (dtbuf), "%c", gmtime (&st)); printf ("Всемирное время конца 32-разрядного отсчета: %s\n", dtbuf);

/* Преобразуем эту дату в формат ISO 8601:2000 */ if (strptime (dtbuf, "%c", &stm) == NULL) { perror ("STRPTIME"); } else { (void) strftime (dtbuf, sizeof (dtbuf), "%F", &stm); printf ("Дата конца 32-разрядного отсчета в формате ISO 8601:2000: %s\n", dtbuf); }

return (0); }

Листинг 12.13. Пример программы, использующей функции преобразования данных о времени.

Возможные результаты выполнения этой программы показаны в листинге 12.14.

Текущее всемирное время: Sat Jan 3 13:54:02 2004 Текущее местное время: Sat Jan 3 16:54:02 2004 День недели 01 января 2038 года: Friday Число секунд от начала отсчета в начале 2038 года (шест.): 7fe7ed50 Всемирное время конца 32-разрядного отсчета: Tue Jan 19 03:14:07 2038 Дата конца 32-разрядного отсчета в формате ISO 8601:2000: 2038-01-19

Листинг 12.14. Возможные результаты работы программы, использующей функции преобразования данных о времени.

Последовательность инструкций языка C

char dtbuf []; time_t st; (void) strftime (dtbuf, sizeof (dtbuf), "%c", localtime (&st));

является стандартной для получения текущего времени в текстовом виде. (Разумеется, вместо "%c" допустим другой спецификатор преобразования.) Нужно помнить только, что функции gmtime() и localtime() возвращают указатели на статические структуры, содержимое которых, возможно, перезаписывается при каждом вызове, поэтому, если оно понадобится в дальнейшем, его следует скопировать в собственные объекты.


Содержание раздела