#include <time.h> предоставляет календарное время и чтение счётчика тактов. time/gmtime/localtime/asctime связаны с реализацией контроллера; difftime/mktime/ctime/strftime экспортируются из библиотеки Arm. Их поведение нельзя считать полностью аналогичным единой настроенной libc настольной ОС.

Типы и единицы

time_t и clock_t — uint32_t. time_t хранит секунды Unix UTC в диапазоне 0..4294967295: от 01.01.1970 00:00:00 до 07.02.2106 06:28:15 UTC. У него нет представления отрицательной даты до эпохи. clock_t хранит такты, а не секунды и не миллисекунды.

  struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
};
  

У tm_mon диапазон 0..11, tm_year — число лет после 1900, tm_mday начинается с 1, tm_wday — 0..6 (воскресенье 0), tm_yday — 0..365. Часы 0..23, минуты и обычные секунды 0..59. Обёртки gmtime/localtime устанавливают tm_isdst=0; автоматического перехода на летнее время нет.

clock

  #define CLOCKS_PER_SEC 168000000
#define CLOCKS_PER_MS  168000
#define CLOCKS_PER_MKS 168
#define clock() (*(volatile clock_t *)0xE0001004)
  

Макрос читает DWT_CYCCNT — общий счётчик тактов процессора. Это не суммарное процессорное время только вашего сценария. При 168 МГц uint32_t оборачивается примерно через 25,6 секунды. Для короткого интервала вычитайте сырые значения до деления; разница корректна при интервале короче одного оборота.

  #include <stdio.h>
#include <time.h>

int main(void) {
    clock_t begin = clock();
    volatile uint32_t sum = 0;
    for (uint32_t i = 0; i < 1000; i++) {sum += i;}
    uint32_t elapsed = (uint32_t)(clock() - begin);
    printf("Elapsed: %lu us\n", (unsigned long)(elapsed / CLOCKS_PER_MKS));
    return 0;
}
  

time

  time_t time(time_t *timer);
  

Возвращает текущий sysUnixTime в секундах UTC. Если timer не NULL, также записывает его туда. time(NULL) допустим. Эта функция не устанавливает часы; корректность текущей даты зависит от настройки RTC/SNTP контроллера.

difftime

  double difftime(time_t time1, time_t time0);
  

Возвращает разницу time1-time0 в секундах как double. Для измерения длительности при коррекции RTC предпочтителен счётчик millis(), а не календарное время.

gmtime

  struct tm *gmtime(const time_t *timer);
  

Преобразует time_t в UTC. В этой реализации NULL означает текущее время. Возвращает указатель на статическую структуру; её не нужно освобождать. Следующий вызов gmtime перезаписывает результат — для хранения сделайте копию.

localtime

  struct tm *localtime(const time_t *timer);
  

Преобразует UTC с добавлением фиксированного часового пояса контроллера в часах. NULL означает текущее время. Результат хранится в отдельной статической структуре, повторный вызов localtime его перезаписывает. Автоматический DST не применяется.

Смещение вычисляется в int64_t. Поэтому time_t=0 и отрицательный пояс корректно дают дату 1969 года, а UINT32_MAX с положительным поясом — более позднее время 2106 года без оборачивания в начало эпохи. Передать такой отрицательный timestamp обратно через time_t нельзя.

  #include <stdio.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    struct tm *result = localtime(&now);
    if (result == NULL) {return 1;}
    struct tm saved = *result;
    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
           saved.tm_year + 1900, saved.tm_mon + 1, saved.tm_mday,
           saved.tm_hour, saved.tm_min, saved.tm_sec);
    return 0;
}
  

mktime

  time_t mktime(struct tm *value);
  

Библиотечное преобразование структуры календаря в time_t с нормализацией полей структуры. Это не обёртка над настройкой часового пояса контроллера: не считайте mktime обратной функцией пользовательского localtime при ненулевом поясе. При ошибке стандартное возвращаемое значение — (time_t)-1, которое в этом типе совпадает с UINT32_MAX.

Заполняйте все поля структуры, включая tm_isdst, и используйте допустимые даты. Обработка библиотекой Arm граничных дат не подтверждена аппаратными тестами обёрток gmtime/localtime.

asctime

  char *asctime(const struct tm *value);
  

Форматирует поля tm на английском, возвращая статический буфер с \n и нулём в конце. NULL возвращает NULL; остальные поля, включая tm_wday=0..6 и tm_mon=0..11, должны быть корректны. Буфер перезаписывается следующим вызовом.

В текущей обёртке день печатается с ведущим нулём: Thu Jan 01 00:00:00 1970\n. Это отличие от стандартного asctime с пробелом перед однозначным днём. Для своего формата используйте strftime.

ctime

  char *ctime(const time_t *timer);
  

Экспортирована библиотечная ctime. Она не вызывает пользовательскую обёртку localtime этого API и не гарантирует применение часового пояса контроллера. Передавайте действительный указатель на time_t. Для отображения времени с поясом устройства явно используйте localtime(), затем strftime() или asctime().

strftime

  size_t strftime(char *s, size_t max, const char *format, const struct tm *value);
  

Форматирует уже готовую структуру tm, без самостоятельного пересчёта часового пояса. max включает место для нуля. При успехе возвращает длину без нуля, при нехватке места — 0. При возврате 0 не полагайтесь на содержимое буфера.

Основные поля: %Y — год, %m — месяц, %d — день, %H/%M/%S — часы/минуты/секунды, %a/%b — английские сокращения дня/месяца, %% — процент. Настройка locale и системного TZ через стандартную библиотеку сценарию не предоставлена; не рассчитывайте на %z/%Z как на источник пояса контроллера.