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

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

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

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

Ответ 1

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

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

#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 требуется вложенный typedefs для описания его 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;

И тогда можно было бы записать return 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

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