В случае успеха strptime() возвращает указатель на следующий необработанный символ в str. (Это пригодится, если строка содержит дополнительную информацию для обработки вызывающей программой.) Если полная строка формата не может быть подобрана, функция strptime() возвращает значение NULL, чтобы показать, что возникла ошибка.
Спецификация формата, заданная функцией strptime(), похожа на ту, что задается scanf(3). В ней содержатся следующие типы символов:
• спецификации преобразования, начинающиеся с символа процента (%);
• пробельные символы, соответствующие нулю или большему количеству пробелов во введенной строке;
• непробельные символы (отличающиеся от %), которые должны соответствовать точно таким же символам во введенной строке.
Спецификации преобразования похожи на те, которые задаются в функции strftime() (см. табл. 10.1). Основное отличие заключается в их более общем характере. Например, спецификаторы %a и %A могут принять название дня недели как в полной, так и в сокращенной форме, а %d или %e могут использоваться для чтения дня месяца, если он может быть выражен одной цифрой с ведущим нулем или без него. Кроме того, регистр символов игнорируется. Например, для названия месяца одинаково подходят May и MAY. Строка %% применяется для соответствия символу процента во вводимой строке. Дополнительные сведения можно найти на странице руководства strptime(3).
Реализация strptime(), имеющаяся в библиотеке glibc, не вносит изменений в те поля структуры tm, которые не инициализированы спецификаторами из аргумента format. Это означает, что для создания одной структуры tm на основе информации из нескольких строк, из строки даты и строки времени, мы можем воспользоваться серией вызовов strptime(). Хотя в SUSv3 такое поведение допускается, оно не является обязательным, и поэтому полагаться на них в других реализациях UNIX не стоит. В портируемом приложении, прежде чем вызвать strptime(), нужно обеспечить наличие в аргументах str и format входящей информации, которая установит все поля получаемой в итоге структуры tm, или же предоставить подходящую инициализацию структуры tm. В большинстве случаев достаточно задать всей структуре нулевые значения, используя функцию memset(). Но нужно иметь в виду, что значение 0 в поле tm_mday соответствует в glibc-версии и во многих других реализациях функции преобразования времени
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
#include
#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]);