GNU-библиотека C также предоставляет две другие функции, которые служат той же цели, что и strptime(): это getdate() (широкодоступная и указанная в SUSv3) и ее реентерабельный аналог getdate_r() (не указанный в SUSv3 и доступный только в некоторых других реализациях UNIX). Здесь эти функции не рассматриваются, потому что они для указания формата, применяемого при сканировании даты, используют внешний файл (указываемый с помощью переменной среды DATEMSK), что затрудняет их применение, а также создает бреши безопасности в set-user-ID-программах.
Использование функций strptime() и strftime() показано в программе, код которой приводится в листинге 10.3. Эта программа получает аргумент командной строки с датой и временем, преобразует их в календарное время, разбитое на компоненты, с помощью функции strptime(), а затем выводит результат обратного преобразования, выполненного функцией strftime(). Программа получает три аргумента, два из которых обязательны. Первый аргумент является строкой, содержащей дату и время. Второй аргумент — спецификация формата, используемого функцией strptime() для разбора первого аргумента. Необязательный третий аргумент — строка формата, используемого функцией strftime() для обратного преобразования. Если этот аргумент не указан, применяется строка формата по умолчанию. (Функция setlocale(), используемая в этой программе, рассматривается в разделе 10.4.) Примеры применения этой программы показаны в следующей записи сеанса работы с оболочкой:
$ ./strtime "9:39:46pm 1 Feb 2011" "%I:%M:%S%p %d %b %Y"
calendar time (seconds since Epoch): 1296592786
strftime() yields: 21:39:46 Tuesday, 01 February 2011 CET
Следующий код похож на предыдущий, но на этот раз формат для strftime() указан явным образом:
$ ./strtime "9:39:46pm 1 Feb 2011" "%I:%M:%S%p %d %b %Y" "%F %T"
calendar time (seconds since Epoch): 1296592786
strftime() yields: 2011-02-01 21:39:46
Листинг 10.3. Извлечение и преобразование данных календарного времени
time/strtime.c
#define _XOPEN_SOURCE
#include <time.h>
#include <locale.h>
#include "tlpi_hdr.h"
#define SBUF_SIZE 1000
int
main(int argc, char *argv[])
{
struct tm tm;
char sbuf[SBUF_SIZE];
char *ofmt;
if (argc < 3 || strcmp(argv[1], "-help") == 0)
usageErr("%s input-date-time in-format [out-format]\n", argv[0]);
if (setlocale(LC_ALL, "") == NULL)
errExit("setlocale"); /* Использование настроек локали при преобразовании */
memset(&tm, 0, sizeof(struct tm)); /* Инициализация 'tm' */
if (strptime(argv[1], argv[2], &tm) == NULL)
fatal("strptime");
tm.tm_isdst = -1; /* Не устанавливается функцией strptime(); заставляет функцию
mktime() определить действие режима летнего времени */
printf("calendar time (seconds since Epoch): %ld\n", (long) mktime(&tm));
ofmt = (argc > 3)? argv[3]: "%H:%M:%S %A, %d %B %Y %Z";
if (strftime(sbuf, SBUF_SIZE, ofmt, &tm) == 0)
fatal("strftime returned 0");
printf("strftime() yields: %s\n", sbuf);
exit(EXIT_SUCCESS);
}
time/strtime.c
Разные страны (а иногда даже и разные регионы одной страны) находятся в разных часовых поясах и режимах действия летнего времени. Программы, где используется ввод и вывод времени, должны учитывать часовой пояс и режим действия летнего времени той системы, в которой они запускаются. К счастью, все эти особенности обрабатываются средствами библиотеки языка C.
Определение часовых поясов
Информация о часовом поясе характеризуется, как правило, обширностью и нестабильностью. Поэтому, вместо того, чтобы вносить ее в код программ или библиотек напрямую, система хранит эту информацию в файлах в стандартных форматах.
Эти файлы находятся в каталоге /usr/share/zoneinfo. Каждый файл в нем содержит информацию о часовом поясе конкретной страны или региона. Файлы названы в соответствии с тем часовым поясом, описание которого в них дается, поэтому там можно найти файлы с такими именами, как EST (US Eastern Standard Time — североамериканское восточное время), CET (Central European Time — центральноевропейское время), UTC, Turkey и Iran. Кроме того, для создания иерархии групп, связанных с часовыми поясами, могут использоваться подкаталоги. Например, в каталоге Pacific можно найти файлы Auckland, Port_Moresby и Galapagos. Когда мы указываем программе, какой именно часовой пояс использовать, на самом деле указывается относительное путевое имя для одного из файлов часового пояса в этом каталоге.