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

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

10.3. Часовые пояса

Разные страны (а иногда даже и разные регионы одной страны) находятся в разных часовых поясах и режимах действия летнего времени. Программы, где используется ввод и вывод времени, должны учитывать часовой пояс и режим действия летнего времени той системы, в которой они запускаются. К счастью, все эти особенности обрабатываются средствами библиотеки языка C.

Определение часовых поясов

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

Эти файлы находятся в каталоге /usr/share/zoneinfo. Каждый файл в нем содержит информацию о часовом поясе конкретной страны или региона. Файлы названы в соответствии с тем часовым поясом, описание которого в них дается, поэтому там можно найти файлы с такими именами, как EST (US Eastern Standard Time — североамериканское восточное время), CET (Central European Time — центральноевропейское время), UTC, Turkey и Iran. Кроме того, для создания иерархии групп, связанных с часовыми поясами, могут использоваться подкаталоги. Например, в каталоге Pacific можно найти файлы Auckland, Port_Moresby и Galapagos. Когда мы указываем программе, какой именно часовой пояс использовать, на самом деле указывается относительное путевое имя для одного из файлов часового пояса в этом каталоге.