Книга: Linux программирование в примерах

6.1.3.2. Сложное форматирование времени: strftime()

6.1.3.2. Сложное форматирование времени: strftime()

Хотя часто достаточно использования asctime() и ctime(), у них есть также и ограничения:

• Формат вывода фиксирован. Нет способа изменить порядок элементов.

• В вывод не включаются сведения о часовом поясе.

• В выводе используются сокращенные названия месяца и дня.

• В выводе используются английские названия месяцев и дней.

По этим причинам C89 ввело стандартную библиотечную процедуру strftime():

#include <time.h> /* ISO С */
size_t strftime(char *s, size_t max, const char *format,
 const struct tm *tm);
strftime()
сходна с sprintf(). Ее аргументы следующие:

char *s

Буфер для форматированной строки.

size_t max

Размер буфера.

const char *format

Форматирующая строка.

const struct tm *tm

Указатель на struct tm, представляющий разложенное время, которое надо отформатировать.

Форматирующая строка содержит символы букв, смешанные о описателями преобразования, указывающими, что должно быть помещено в строку, такими, как полное имя дня недели, час в соответствии с 24-часовым или 12-часовым циклом, наличие указателей am или p.m[64], и т.д. (Вскоре будут приведены примеры.)

Если всю строку можно отформатировать с использованием не более max символов, возвращаемое значение представляет собой число символов, помещенных в s, не включая завершающий нулевой байт. В противном случае, возвращаемое значение ноль. В последнем случае содержание s «неопределенно». Следующий простой пример дает представление об использовании strftime():

#include <stdio.h>
#include <time.h>
int main(void) {
 char buf[100];
 time_t now;
 struct tm *curtime;
 time(&now);
 curtime = localtime(&now);
 (void)strftime(buf, sizeof buf,
  "It is now %A, %B %d, %Y, %I:%M %p", curtime);
 printf("%sn", buf);
 exit(0);
}

После запуска эта программа выводит что-то типа:

It is now Thursday, May 22, 2003, 04:15 PM

В табл. 6.2 предоставлен полный список описателей преобразования, их возможные альтернативные представления и их значения. Вдобавок стандарт C99 добавил к списку дополнительные описатели; новые для C99 описатели помечены символом ?.

Таблица 6.2. Описатели преобразования формата strftime()

Описатель C99 Значение
%a Локальное сокращенное название дня недели.
%A Локальное полное название дня недели.
%b Локальное сокращенное название месяца.
%B Локальное полное название месяца.
%c, %Ec Локальное «подходящее» представление даты и времени
%C, %EC ? Век (00–99)
%d, %Od День месяца (01–31)
%D ? То же, что %m/%d/%y
%e, %Oe ? День месяца. Одна цифра дополняется пробелом (1–31).
%F ? То же, что и %Y-%m-%d (формат даты ISO 8601)
%g ? Две последние цифры, основанной на неделе года (00–99).
%G ? Основанный на неделе год ISO 8601
%h ? То же, что и %b
%H, %OH Час в 24-часовом цикле (00–23)
%I, %OI Час в 12-часовом цикле (01–12)
%j День года (001–366)
%m, %Om Месяц в виде числа (01–12).
%M, %OM Минута в виде числа (00–59)
%n ? Символ конца строки ('n')
%p Локальное обозначение a.m./p.m.
%r ? Локальное время в 12-часовом цикле
%R ? Тоже, что и %H:%M
%S, %OS Секунда в виде числа (00–60)
%t ? Символ табуляции ('t')
%T ? То же, что и %H:%M:%S (формат ISO 8601).
%u, %Ou ? Число дня недели ISO 8601, понедельник = 1 (1–7).
%U, %OU Номер недели, первое воскресенье является первым днем недели 1 (00–53)
%V, %OV ? Номер недели ISO 8601 (01–53)
%w, %Ow День недели как число, воскресенье = 0 (0–6).
%W, %OW Номер недели, первый понедельник является первым днем недели 1 (00–53)
%x, %Ex Локальное «подходящее» представление даты
%X, %EX Локальное «подходящее» представление времени.
%y, %Ey, %Oy Две последние цифры года (00–99)
%Y, %EY Год как число.
%Z Локальный часовой пояс или отсутствие символов, если сведения о часовом поясе недоступны
%% Простой %

Локаль (locale) является способом описания местной специфики, принимая во внимание такие вещи, как язык, кодировка символов и значения по умолчанию для форматирования дат, времени, денежных сумм и т.д. Мы будем иметь с ними дело в главе 13 «Интернационализация и локализация». Пока достаточно понять, что результаты strftime() для одной и той же форматирующей строки могут быть разными в зависимости от настроек текущей локали.

Версии, начинающиеся с %E и %O, предназначены для «альтернативного представления». В некоторых локалях есть несколько способов представления одних и тех же сведений; эти описатели предоставляют доступ к дополнительным представлениям. Если определенная локаль не поддерживает альтернативного представления, strftime() использует обычную версию.

Многие Unix-версии date дают возможность предоставить в командной строке форматирующую строку, начинающуюся с символа '+'. Затем date форматирует текущие дату и время и выводит в соответствии с форматирующей строкой:

$ date + 'It is now %A, %B %d, %Y, %I:%M %p'
It is now Sunday, May 25, 2003, 06:44 PM

Большинство новых описателей C99 происходит от таких существующих реализаций date Unix. Описатели %n и %t не являются в С абсолютно необходимыми, поскольку символы табуляции и конца строки могут быть помещены в строку непосредственно. Однако в контексте форматирующей строки date для командной строки они имеют больше смысла. Поэтому они также включены в спецификацию strftime().

Стандарт ISO 8601 определяет (среди других вещей), как нумеруются недели в пределах года. В соответствии с этим стандартом недели отсчитываются с понедельника по воскресенье, а понедельник является днем недели 1, а не 0. Если неделя, в которой оказывается 1 января, содержит по крайней мере четыре дня нового года, она считается неделей 1. В противном случае, это последняя неделя предыдущего года с номером 52 или 53. Эти правила используются для вычислений описателей форматов %g, %G и %V. (Хотя ограниченным американцам, таким, как автор, эти правила могут показаться странными, они обычно повсюду используются в Европе.)

Многие из описателей стандартов дают результаты, специфичные для текущей локали. Вдобавок некоторые указывают, что они выдают «подходящее» представление для локали (например, %x). Стандарт C99 определяет значения для локали «С». Эти значения перечислены в табл. 6.3

Таблица 6.3. Значения локали «С» для определенных форматов strftime()

Описатель Значение
Первые три символа .
Один из дней Sunday, Monday, …, Saturday
%b Первые три символа
Один из месяцев January, February, …, December
То же, что и %а %b %е %T %Y
%p AM или PM
%r То же, что и %I:%M:%S %p
%x То же, что и %m/%d/%y
%X То же, что и %T.
%Z Определяется реализацией

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

В качестве простого примера рассмотрим создание файлов журнала программы, когда каждый час создается новый файл. Имя файла должно включать дату и время создания:

/* Проверка ошибок для краткости опущена */
char fname[PATH_МАХ]; /* PATH_МАХ находится в <limits.h> */
time_t now;
struct tm *tm;
int fd;
time(&now);
tm = localtime(&now);
strftime(fname, sizeof fname, "/var/log/myapp.%Y-%m-%d-%H:%M", tm);
fd = creat(name, 0600);
...

Формат год-месяц-день-час-минута вызывает сортировку файлов в том порядке, в каком они были созданы.

ЗАМЕЧАНИЕ. Некоторые форматы данных более полезны, чем другие. Например, 12-часовое время двусмысленно, также, как чисто числовые форматы дат. (Что означает '9/11'? Это зависит от того, где вы живете) Сходным образом, годы из двух цифр также являются плохой мыслью. Используйте strftime() благоразумно

Оглавление книги


Генерация: 1.597. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз