Библиотека 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.

Взаимосвязь между функциями библиотеки time.h языка Си
Схема. Функции преобразования типов библиотеки time.h языка Си

Если все же мы хотим увидеть дату, которая была получена в секундах, в "человеческом" виде, проще всего воспользоваться функцией 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