Это было сделано для того, чтобы вы получили максимальную гибкость наряду с компактными размерами. Если вам нужна сверхвысокая точность, вам обычно не нужен очень большой диапазон. И если вам нужен очень большой диапазон, вам обычно не нужна очень высокая точность.
Например, если вы торгуете наносекундами, нужно ли вам постоянно думать о большем, чем +/- 292 года? И если вам нужно подумать о большем диапазоне, микросекунды дают вам +/- 292 тысячи лет.
MacOS system_clock
фактически возвращает микросекунды, а не наносекунды. Так что часы могут идти 292 тысячи лет с 1970 года, пока не переполнятся.
Windows system_clock
имеет точность в 100 нс и, следовательно, имеет диапазон +/- 29,2 тысячи лет.
Если пары сотен тысяч лет все еще недостаточно, попробуйте миллисекунды. Теперь вы находитесь в диапазоне +/- 292 миллиона лет.
Наконец, если вам просто нужно иметь наносекундную точность более пары сотен лет, <chrono>
также позволяет настроить хранилище:
using dnano = duration<double, nano>;
Это дает вам наносекунды, сохраненные как double
. Если ваша платформа поддерживает 128-битный интегральный тип, вы также можете использовать его:
using big_nano = duration<__int128_t, nano>;
Черт возьми, если вы пишете перегруженные операторы для timespec
, вы даже можете использовать это для хранения (хотя я этого не рекомендую).
Вы также можете достичь точности выше наносекунд, но при этом вы пожертвуете диапазоном. Например:
using picoseconds = duration<int64_t, pico>;
Это имеет диапазон всего +/- 0,292 года (несколько месяцев). Так что вы действительно должны быть осторожны с этим. Однако отлично подходит для синхронизации, если у вас есть исходные часы, которые дают вам точность менее наносекунды.
Посмотрите этот видеоролик, чтобы узнать больше о <chrono>
.
Для создания, управления и хранения дат с диапазоном, превышающим срок действия текущего григорианского календаря, я создал этот библиотека дат с открытым исходным кодом, которая расширяет библиотеку <chrono>
календарными службами. Эта библиотека хранит год в виде 16-битного целого числа со знаком, поэтому имеет диапазон +/- 32 000 лет. Его можно использовать следующим образом:
#include "date.h"
int
main()
{
using namespace std::chrono;
using namespace date;
system_clock::time_point now = sys_days{may/30/2017} + 19h + 40min + 10s;
}
Обновить
В комментариях ниже задается вопрос, как «нормализовать» duration<int32_t, nano>
в секунды и наносекунды (а затем добавить секунды к time_point).
Во-первых, я бы поостерегся запихивать наносекунды в 32 бита. Диапазон составляет чуть более +/- 2 секунды. Но вот как я выделяю такие единицы:
using ns = duration<int32_t, nano>;
auto n = ns::max();
auto s = duration_cast<seconds>(n);
n -= s;
Обратите внимание, что это работает, только если n
положительное. Чтобы правильно обрабатывать отрицательные n
, лучше всего сделать следующее:
auto n = ns::max();
auto s = floor<seconds>(n);
n -= s;
std::floor
представлен в C++17. Если вы хотите получить его раньше, вы можете получить его здесь или здесь.
Я неравнодушен к описанной выше операции вычитания, так как считаю ее более читабельной. Но это тоже работает (если n
не отрицательное):
auto s = duration_cast<seconds>(n);
n %= 1s;
1s
появился в C++14. В C++11 вместо этого вам придется использовать seconds{1}
.
Если у вас есть секунды (s
), вы можете добавить их к своим time_point
.
person
Howard Hinnant
schedule
30.05.2017