Как создать собственные часы для использования в функциях std::chrono?

У меня есть произвольная эпоха, например 13 июля 1988 года. По сути, я хочу измерить время относительно этого. Я думал написать собственный класс часов, чтобы я мог написать такой код:

using std::chrono;
time_point<My_Clock> tp;
std::cout << duration_cast<seconds>(tp.time_since_epoch()).count() << std::endl;

Это возможно? Если нет, то какой самый чистый способ сделать это?


person sagargp    schedule 14.05.2013    source источник
comment
Бьюсь об заклад, в стандарте перечислены требования.   -  person chris    schedule 14.05.2013
comment
time_point принимает Clock в качестве шаблона, который является концепцией. Вы можете просто написать свой собственный класс, который удовлетворяет требованиям, предъявляемым этой конкретной концепцией. Но не верьте мне на слово, я просто думаю вслух.   -  person Daniel Kamil Kozar    schedule 14.05.2013
comment
@DanielKamilKozar Я просмотрел источник для system_clock в качестве примера, но я не продвинулся очень далеко. Я не вижу, где указана фактическая эпоха. Я думаю, что это зависит от системы. Где я могу найти документацию о том, как сделать что-то подобное?   -  person sagargp    schedule 14.05.2013


Ответы (1)


Трудная часть написания этих пользовательских часов — выяснить, как написать их функцию now(). В приведенном ниже примере я основываю now() на основе system_clock now(). Сначала я выполняю некоторую детективную работу, чтобы обнаружить, что моя system_clock имеет эпоху Нового 1970 года, пренебрегая високосными секундами. Это известно как время unix. Как оказалось, каждая реализация, о которой я знаю (и я думаю, что проверил их все), имеет одну и ту же эпоху (но это не указано в стандарте С++ 11).

Далее я вычисляю, что 13 июля 1988 г. составляет 6768 дней после 01 января 1970 г. Используя эти два факта, остальное легко:

#include <chrono>

struct My_Clock
{
    typedef std::chrono::seconds              duration;
    typedef duration::rep                     rep;
    typedef duration::period                  period;
    typedef std::chrono::time_point<My_Clock> time_point;
    static const bool is_steady =             false;

    static time_point now() noexcept
    {
        using namespace std::chrono;
        return time_point
          (
            duration_cast<duration>(system_clock::now().time_since_epoch()) -
            hours(6768*24)
          );
    }
};

MyClock нужны вложенные определения типов для описания его duration, rep, period и time_point. Основываясь на вашем вопросе, я выбрал seconds вместо duration, но вы можете выбрать что угодно.

Для функции now() я просто вызываю system_clock::now() и вычитаю эпоху в секундах. Я немного поумнел в этом вычислении, записав все в терминах MyClock::duration, чтобы мне было легче изменить duration. Обратите внимание, что я смог вычесть из эпохи hours, что неявно преобразуется в duration (то есть seconds). В качестве альтернативы я мог бы создать себе duration дней:

typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period,
                                                       std::ratio<24>>> days;

И тогда можно было бы написать возвращение now():

        return time_point
          (
            duration_cast<duration>(system_clock::now().time_since_epoch()) -
            days(6768)
          );

Во всяком случае, теперь вы можете использовать это как:

#include <iostream>

int
main()
{
    using namespace std::chrono;
    time_point<My_Clock> tp = My_Clock::now();
    std::cout << tp.time_since_epoch().count() << '\n';
}

Который для меня только что распечатал:

786664963

Что показывает, что сегодня (16 июня 2013 г.) примерно 24,9 года после 13 июля 1988 г.

person Howard Hinnant    schedule 16.06.2013
comment
Это круто, именно то, что мне было нужно. Спасибо! - person sagargp; 22.06.2013
comment
Начиная с С++ 20 стандарт определяет эпоху Unix (1970-01-01) для system_clock. - person John Gordon; 29.07.2021