Библиотека time языка C. Работа со временем
Создано: 25.09.2025
В языке Си есть библиотека для работы со временем (в том числе датами), функции и типы данных которой подключаются с помощью заголовочного файла time.h. Одной из функций мы уже пользовались для генерации псевдослучайных чисел. Однако сразу после того урока изучать библиотеку времени было бы затруднительно, так как в ней используются указатели и структуры.
Вспомним, что с помощью функции time() мы получали целое число, значение которого зависело от постоянно меняющегося времени. Это время соответствует текущему системному времени в секундах, прошедших с 1 января 1970 г (в некоторых ОС возможно с 1900 г). Кроме того, тип данный того, что возвращает time(), ‒ не совсем целое число, а time_t, описанный в заголовочном файле time.h. Однако в зависимости от ОС time_t определен как int или long int. Следовательно, формат вывода значения будет %d или %ld.
Ранее мы передавали в time() значение NULL, получали текущее время, которое сразу передавали в функцию srand(), чтобы задать зерно для генерации случайных чисел. Теперь мы будем присваивать текущее время переменной, имеющей тип time_t.
С другой стороны, time() можно вызывать по-другому. Если передать не NULL, а адрес переменной типа time_t, то функция запишет в эту переменную текущее время. То есть функция и возвращает данные (всегда), и меняет значение аргумента (только если передан адрес).
#include <stdio.h> #include <time.h> int main() { time_t var1; var1 = time(NULL); printf("var1 = %ld", var1); getchar(); time_t var2; time(&var2); printf("var2 = %ld", var2); getchar(); time_t var3, var4; var4 = time(&var3); printf("var3 = %ld\n", var3); printf("var4 = %ld\n", var4); }
Пример выполнения программы:
var1 = 1758675472 var2 = 1758675475 var3 = 1758675479 var4 = 1758675479
В примере getchar() используется для выполнения задержки между вызовами time(). Чтобы увидеть разные значения, перед нажатием Enter пользователю следует немного выжидать. Две последние переменные в любом случае будут содержать одинаковые значения, так как они являются результатом одного и того же вызова time().
Время, выраженное числом в секундах, мало о чем нам говорит. Но оно удобно для сравнений и вычисления промежутков времени:
time_t start, finish; int answer; start = time(NULL); printf("Сколько будет 34 - 58?\n"); do { scanf("%d", &answer); } while (answer != -24); finish = time(NULL); printf("Вы решали %.0f сек.\n", difftime(finish, start));
Пример выполнения:
Сколько будет 34 - 58? 80 56 -24 Вы решали 9 сек.
Функция difftime() вычисляет разницу между двумя объектами time_t. Если сначала передать меньшее значение, то возвращаемое ею число будет отрицательным. Вместо difftime() можно просто вычесть значение одной переменной из другой, однако в этом случае тип данных будет длинным целым, а не double.
Если все же мы хотим увидеть дату, которая была получена в секундах, в "человеческом" виде, проще всего воспользоваться функцией ctime(), которая вернет строку, содержащую информацию о времени и дате. Передавать этой функции надо адрес переменной типа time_t, а не ее значение.
time_t var1 = time(NULL); printf("%s", ctime(&var1));
Пример выполнения:
Wed Sep 24 04:56:09 2025
Если мы хотим выводить данные не в таком жестко заданном формате или нам нужны отдельные компоненты времени (например, только время или дата) для выполнения с ними в дальнейшем различных операций, то нет другого пути, как преобразовать значение time_t в структурный тип struct tm.
Сделать это можно с помощью двух функций ‒ localtime() и gmtime(). Обе возвращают указатель на данные типа struct tm, но в первом будут характеристики локального времени, во втором ‒ по UTC.
time_t var = time(NULL); struct tm *varL = localtime(&var); printf("%d\n", varL->tm_hour); printf("%s", asctime(varL)); struct tm *varG = gmtime(&var); printf("%d\n", varG->tm_hour); printf("%s", asctime(varG));
Пример выполнения:
5 Wed Sep 24 05:07:29 2025 2 Wed Sep 24 02:07:29 2025
В примере мы выводим значение только поля tm_hour структуры. Все поля: tm_sec, tm_min, tm_hour, tm_mday, tm_mon (месяцы с 0 до 11), tm_year (годы отсчитываются, начиная с 1900), tm_wday (день недели, 0 ‒ воскресенье), tm_yday (номер дня, начиная с начала года, 0 ‒ первое значение), tm_isdst (признак летнего времени: положительное значение ‒ да, 0 ‒ нет, отрицательное значение ‒ неизвестно).
Также в примере выше используется функция asctime(), которая является аналогом ctime(), но применяемым по отношению к struct tm, а не time_t. Обратите внимание, что переменная, которая передается в asctime() уже содержит адрес (является указателем).
Более широкие возможности у функции strftime(), которая позволяет выводить дату в произвольно заданном формате. В качестве аргументов она принимает строку для записи данных с указанием ее размера, строку со спецификаторами форматов характеристик времени, указатель на структуру типа struct tm откуда данные берутся.
time_t t = time(NULL); struct tm *st = localtime(&t); char output[30]; strftime(output, sizeof(output), "%T %D", st); printf("%s\n", output); strftime(output, sizeof(output), "%H:%M:%S %d-%m-%Y", st); printf("%s\n", output);
Пример выполнения:
06:31:39 09/24/25 06:31:39 24-09-2025
Все спецификации форматов времени, которых очень много, можно посмотреть в той или иной документации (например, в Bash с помощью команды man strftime).
Нередко требуется дату получить с ввода, сохранить в программе и использовать для выполнения тех или иных операций с датами. Здесь мы сталкиваемся с обратной задачей: есть строка, требуется ее привести к типу struct tm или time_t. Для таких случаев есть функция strptime(). Чтобы она работала, необходимо определить макрос, содержащийся в константе _XOPEN_SOURCE (возможно не для всех ОС).
#define _XOPEN_SOURCE #include <stdio.h> #include <time.h> int main() { struct tm t; char date[30]; printf("Введите дату в формате h:m dd-mm-yyyy\n"); fgets(date, sizeof(date), stdin); strptime(date, "%H:%M %d-%m-%Y", &t); printf("%d\n", t.tm_hour); printf("%d\n", t.tm_min); printf("%d !\n", t.tm_sec); // ! printf("%d !\n", t.tm_wday); // ! printf("%d\n", t.tm_mday); printf("%d\n", t.tm_mon); printf("%d\n", t.tm_year); }
Пример выполнения:
Введите дату в формате h:m dd-mm-yyyy 4:08 24-09-2025 4 8 32768 ! 3 ! 24 8 125
Обратите внимание, что, хотя мы не задаем день недели, он правильно записывается в соответствующее поле структуры (tm_wday). Однако поле tm_sec видимо принимает максимально возможное для себя значение. Чтобы его изменить, следует присвоить значение явно.
Помимо рассмотренных в уроке функций в библиотеке time.h имеется функция clock(), которая не принимает аргументы и возвращает значение типа clock_t (аналог long int). Это значение обозначает время, но измеряемое не в секундах, а в тактах процессора. Значение отсчитывается от начала выполнения программы. Количество тактов в секунде можно узнать с помощью константы CLOCKS_PER_SEC.
#include <stdio.h> #include <stdlib.h> #include <time.h> #define N 10000 int main() { clock_t start = clock(); for (int i = 1; i <= N; i++) rand(); clock_t finish = clock(); printf("%ld\n", finish - start); printf("%ld\n", CLOCKS_PER_SEC); }
Пример выполнения:
791 1000000
- Заполните поля структуры типа
struct tmс ввода. Чтобы увидеть получившуюся дату, выведите ее с помощьюasctime(). - Получите значение текущего системного времени, приведите его к структурному типу. Передвиньте дату вперед на 10 дней (возможно потребуется поменять месяц или даже год). Используя функцию
mktime(), которая выполняет конвертациюstruct_tmвtime_t, преобразуйте время обратно в секунды. Найдите разницу с исходным значением и убедитесь, что она соответствует 10 дням (в 1 дне 86400 секунд).