В стандарте C++20 библиотека chrono из C++11 получила важные дополнения. Наиболее заметными из них являются: календарь, поддержка часовых поясов, тип времени суток и мощный функционал форматирования временных интервалов.
Библиотека времени в C++11
Для начала вам потребуется базовое понимание библиотеки chrono. Стандарт C++11 ввел три основных компонента для работы со временем:
Момент времени (англ. «Time Point») — задается точкой отсчета (так называемой «эпохой») и сопутствующим временным интервалом.
Временной интервал/Длительность (англ. «Time duration») — разница между двумя моментами времени. Определяется числом «тиков» времени.
Часы (англ. «Clock») — состоят из точки отсчета (эпохи) и «тика» времени. Эта информация позволяет рассчитать текущее время.
Все три компонента зависят друг от друга.
Расширение библиотеки chrono в C++20
Стандарт C++20 добавляет в библиотеку chrono новые компоненты:
Время суток (англ. «Time of day») — это временной интервал, ведущий свой отсчет с полуночи, представляемый в виде часов, минут, секунд и долей секунды.
Календарь (англ. «Calendar») — обозначает различные календарные даты, такие как: год, месяц, день недели или n-й день недели.
Часовой пояс (англ. «Time-zone») — представляет собой время, характерное для определенной географической области.
По сути, функционал часовых поясов (C++20) основан на функционале календаря (C++20), а функционал календаря (C++20) основан на первоначальном функционале библиотеки chrono (C++11).
Но это еще не всё. Расширения библиотеки включают в себя новые часы. Благодаря библиотеке форматирования в C++20, мы теперь можем легко считывать/записывать временные интервалы.
Библиотека date
При написании данной статьи еще ни один компилятор C++ не реализовал поддержку расширения библиотеки chrono из стандарта C++20. Но не стоит отчаиваться, ведь мы можем воспользоваться её прототипом — библиотекой date от Howard Hinnant, которая, по сути, является надмножеством расширенного функционала работы со временем из стандарта C++20.
Существуют различные способы использования данной библиотеки:
Онлайн-компилятор wandbox. Говард уже загрузил заголовочный файл date.h, которого будет достаточно для наших экспериментов с календарем и новым типом std::time_of_day. Также вы можете сами скопировать содержимое актуального файла date.h в соответствующую вкладку wandbox-а:
Либо же можно скопировать заголовочный файл date.h в папку с заголовочными файлами вашего компилятора C++.
Требуемый стандарт C++
В целом, для работы с библиотекой date, компилятора, поддерживающего стандарт C++14, будет достаточно. Правда, есть одно исключение, а именно:
1 2 |
auto timeOfDay = date::time_of_day(10.h + 98min + 2020s + 0.5s); // (1) auto timeOfDay = date::hh_mm_ss(10.h + 98min + 2020s + 0.5s); // (2) |
В своих первых попытках я использовал первый вариант (1) вызова функции. Данная строка требует вывод параметров шаблона класса для псевдонимов шаблонов, т.к. time_of_day
— это псевдоним для hh_mm_ss
, т.е. time_of_day_day = hh_mm_ss<Duration>
. Когда вы заменяете псевдоним шаблоном класса, например, во второй строке (2), то вам потребуется компилятор с поддержкой стандарта C++17, т.к. вывод параметра шаблона класса — это прерогатива именно C++17.
Примечание: В C++20 time_of_day
был переименован в hh_mm_ss
. Говард Хиннант, создатель библиотеки date и дизайнер дополнения chrono, дал крайне важный совет: «Используйте hh_mm_ss
вместо time_of_day
. Название time_of_day
было изменено на hh_mm_ss
во время процесса стандартизации под требования C++20, и поэтому название time_of_day
остается только в рамках обеспечения обратной совместимости с ранее написанными программами».
Портирование под C++20
Когда вы пользуетесь функциями библиотеки date, являющимися частью стандарта C++20, то адаптировать программу под использование непосредственно со стандартом C++20 не составит большого труда. Замените заголовочные файлы библиотеки date заголовочным файлом <chrono>, а пространство имен date
— пространством имен std::chrono
:
1 2 3 4 5 6 7 8 9 10 |
#include "date.h" //#include <chrono> int main() { using namespace std::chrono_literals; auto am = date::is_am(10h); // auto am = std::chrono::is_am(10h); } |
Теперь я расскажу вам о расширении библиотеки chrono в C++20.
Время суток (Time of Day)
std::chrono::hh_mm_ss
— это время, прошедшее с полуночи, в виде часов, минут, секунд и долей секунд. Данный тип обычно используется в качестве инструмента форматирования. Для начала давайте посмотрим на следующую таблицу с кратким обзором объекта tOfDay
класса std::chrono::hh_mm_ss
:
Функция | Описание |
tOfDay.hours() | Возвращает часы |
tOfDay.minutes() | Возвращает минуты |
tOfDay.seconds() | Возвращает секунды |
tOfDay.subseconds() | Возвращает доли секунды |
tOfDay.to_duration() | Возвращает в секундах время, прошедшее с полуночи |
std::chrono::make12(hour) std::chrono::make24(hour) |
Возвращает 12- (24-) часовой эквивалент 24- (12-) часового формата времени |
std::chrono::date::is_am(hour) std::chrono::date::is_pm(hour) |
Определяет, соответствует ли время, заданное в 24-часовом формате, 12-часовому формату (am/pm) |
Пример программы, использующей вышеописанные функции:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// timeOfDay.cpp #include "date.h" #include <iostream> int main() { using namespace date; // (3) using namespace std::chrono_literals; std::cout << std::boolalpha << std::endl; auto timeOfDay = date::hh_mm_ss(10.5h + 98min + 2020s + 0.5s); // (1) std::cout<< "timeOfDay: " << timeOfDay << std::endl; // (2) std::cout << std::endl; std::cout << "timeOfDay.hours(): " << timeOfDay.hours() << std::endl; // (4) std::cout << "timeOfDay.minutes(): " << timeOfDay.minutes() << std::endl; // (4) std::cout << "timeOfDay.seconds(): " << timeOfDay.seconds() << std::endl; // (4) std::cout << "timeOfDay.subseconds(): " << timeOfDay.subseconds() << std::endl; // (4) std::cout << "timeOfDay.to_duration(): " << timeOfDay.to_duration() << std::endl; // (5) std::cout << std::endl; std::cout << "date::hh_mm_ss(45700.5s): " << date::hh_mm_ss(45700.5s) << '\n'; // (6) std::cout << std::endl; std::cout << "date::is_am(5h): " << date::is_am(5h) << std::endl; // (7) std::cout << "date::is_am(15h): " << date::is_am(15h) << std::endl; // (7) std::cout << std::endl; std::cout << "date::make12(5h): " << date::make12(5h) << std::endl; // (7) std::cout << "date::make12(15h): " << date::make12(15h) << std::endl; // (7) } |
Результат выполнения программы:
timeOfDay: 12:41:40.500000
timeOfDay.hours(): 12h
timeOfDay.minutes(): 41min
timeOfDay.seconds(): 40s
timeOfDay.subseconds(): 0.500000s
timeOfDay.to_duration(): 45700.500000s
date::hh_mm_ss(45700.5s): 12:41:40.500000
date::is_am(5h): true
date::is_am(15h): false
date::make12(5h): 5h
date::make12(15h): 3h
В строке (1) я создаю новую переменную timeOfDay
— экземпляр класса std::chrono::hh_mm_ss
. Благодаря существующим в библиотеке chrono (C++14) литералам, я могу просто использовать несколько временных интервалов для инициализации переменной timeOfDay
. С помощью стандарта C++20 вы можете напрямую выводить значение переменной timeOfDay
(2). Кстати говоря, именно поэтому мне пришлось подключить пространство имен date
в строке (3). Остальное должно быть легко читаемо. Строки под номером (4) отображают компоненты времени в часах, минутах, секундах и долях секунды. Строка (5) возвращает прошедшее с полуночи время в секундах. Строка (6) более интересна: заданные секунды соответствуют времени, отображаемому в строке (2). Строка (7) возвращает, принадлежит ли заданный час временному интервалу в формате a.m. Строка (8) возвращает 12-часовой эквивалент заданного часа.