Наносекунды и Chrono C ++

2018-10-01 00:06:16.700000000

У меня есть файл данных временного ряда с отметками времени, как указано выше. Мне нужно преобразовать это в наносекунды из эпохи, затем мне нужно будет добавить милли, микро или наносекунды к метке времени (сдвиг). Наконец, для выбранных записей верните его к формату, указанному выше.

У меня проблемы с созданием точки времени - и с тем, как представлять наносекунды ... Он отлично работает с микропроцессорами.

Могу я попросить некоторую помощь с фрагментом кода ниже ... а также, когда у меня есть наносекунды от эпохи - как мне вернуться к метке времени, подобной той, что указана выше.

std::string ts("23 01 2020 20:59:59.123456789");

XXXX (ts);

void XXXXX (string timestamp)
{
     stringstream temp_ss(timestamp);

     tm temp_time_object = {};

     temp_ss >> get_time (&temp_time_object, "%Y/%m/%d %H:%M:%S");

     chrono::system_clock::time_point temp_time_point = system_clock::from_time_t(mktime(&temp_time_object));
    // chrono::high_resolution_clock::time_point temp_time_point1 = temp_time_point;

    auto  nsecs           =  stol (timestamp.substr (timestamp.find_first_of('.')+1,9));

// +++ This is where I GET stuck forming the time_point....
// I've tried this so many different ways .... 
// Is it that the system_clock cannot accept nanos? 


    temp_time_point += nanoseconds (nsecs);

     auto micro_from_epoch = duration_cast<nanoseconds> (temp_time_point.time_since_epoch()).count();

     cout << micro_from_epoch << endl;

}

person Admiral Kirk    schedule 01.05.2020    source источник
comment
пожалуйста, опубликуйте полученное сообщение об ошибке   -  person bolov    schedule 01.05.2020
comment
проблема с приведенным выше кодом заключается в том, что для наносекунд нет оператора + =. Если я попытаюсь явно добавить использование продолжительности с соотношением 1: 100000000 - он все равно жалуется, что я не могу добавить это к моменту времени.   -  person Admiral Kirk    schedule 01.05.2020
comment
Ваша строковая метка времени - местное время или всемирное координированное время? Если местное время, текущий местный часовой пояс вашего компьютера или какой-либо другой часовой пояс?   -  person Howard Hinnant    schedule 01.05.2020
comment
Предположим, что все временные метки - GMT, UTC + 0   -  person Admiral Kirk    schedule 01.05.2020


Ответы (2)


У меня проблемы с созданием точки времени - и с тем, как представлять наносекунды ... Он отлично работает с микропроцессорами.

Это говорит мне, что ваш system_clock::time_point имеет точность грубее наносекунд (на llvm это микросекунды, в Windows 1/10 микросекунды). Самый простой способ добавить наносекунды к такому time_point:

auto tp = temp_time_point + nanoseconds (nsecs);

Это формирует time_point, который все еще основан на system_clock, но имеет точность "общего типа" system_clock::duration и nanoseconds, которая на практике будет просто nanoseconds.

Предположим, что все временные метки - GMT, UTC + 0

Теперь проблема в том, что mktime преобразуется из локального tm в UTC time_t. Но вы хотите преобразовать из типа поля UTC в последовательный тип UTC.

Это легко сделать в C ++ 20 (я знаю, что у вас его еще нет, выслушайте меня):

#include <chrono>
#include <iostream>
#include <sstream>

std::chrono::sys_time<std::chrono::nanoseconds>
XXXXX(std::string const& timestamp)
{
    using namespace std;
    using namespace std::chrono;
    istringstream temp_ss{timestamp};
    sys_time<nanoseconds> tp;
    temp_ss >> parse("%F %T", tp);
    return tp;
}

int
main()
{
    auto tp = XXXXX("2018-10-01 00:06:16.700000000");
    std::cout << tp.time_since_epoch().count() << "ns\n";
    std::string s = std::format("{:%F %T}", tp);
    std::cout << s << '\n';
}

Это преобразует string в chrono::time_point<system_clock, nanoseconds>, который, очевидно, отличается от вашего system_clock::time_point только тем, что ваш system_clock::time_point имеет более грубую точность, чем nanoseconds.

Затем format используется для преобразования time_point обратно в string.

Вывод:

1538352376700000000ns
2018-10-01 00:06:16.700000000

Теперь я знаю, что полностью соответствующий C ++ 20 <chrono> - редкость в наши дни (он скоро появится). Пока он не дойдет до этого места, существует библиотека <chrono> предварительного просмотра C ++ 20, которая обратно совместима с C ++. 11. Это бесплатно и с открытым исходным кодом. И требует очень мало синтаксических изменений:

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

date::sys_time<std::chrono::nanoseconds>
XXXXX(std::string const& timestamp)
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;
    istringstream temp_ss{timestamp};
    sys_time<nanoseconds> tp;
    temp_ss >> parse("%F %T", tp);
    return tp;
}

int
main()
{
    using namespace date;
    auto tp = XXXXX("2018-10-01 00:06:16.700000000");
    std::cout << tp.time_since_epoch().count() << "ns\n";
    std::string s = format("%F %T", tp);
    std::cout << s << '\n';
}

Вывод:

1538352376700000000ns
2018-10-01 00:06:16.700000000
person Howard Hinnant    schedule 01.05.2020
comment
Ваш последний пример с использованием date.h удивительно прост и понятен. Я просто попробовал перенести его на Mac OS. Я получаю сообщение об ошибке при выполнении: ./bootstrap-vcpkg.sh .... снова посмотрю на него утром и посмотрю, смогу ли я исправить проблему ... Errorsa re: eval: line 162: неожиданный EOF при поиске соответствие `` '' - person Admiral Kirk; 01.05.2020
comment
В этом случае инструмент сборки на основе CMake (или любой другой инструмент управления пакетами) вызовет больше проблем, чем решит. date.h - это библиотека только для заголовков. Просто включите его, и все готово. Если это по-прежнему не решает вашу проблему, дайте мне знать, и я помогу вам начать работу. - person Howard Hinnant; 01.05.2020
comment
так просто - файл заголовка работал отлично .... где я могу найти список спецификаторов формата даты ... например, если моя дата: разделена символом '/' или каким-либо другим форматом ... Я также заметил, что библиотека определяет, если вы предоставляете миллисекунды - и он преобразуется в наносекунды и т.д ... спасибо за вашу помощь. - person Admiral Kirk; 02.05.2020
comment
Вот все флаги синтаксического анализа: howardhinnant.github.io/date/date.html#from_stream_formatting Флаги форматирования очень похожи и находятся в отдельной таблице чуть выше этой. - person Howard Hinnant; 03.05.2020

Вы работаете с прямым преобразованием текста в наносекундное разрешение. По сути, есть две ключевые библиотеки:

  • CCTZ некоторых инженеров Google, хотя (как и многие другие проекты) не является официально выпущенным продуктом Google.

  • date Ховарда Хиннанта, который, вероятно, ответит здесь, прежде чем я закончу печатать; его библиотека является основой содержимого для этого в C ++ 20

Я обернул обе версии для R (через Rcpp), и у меня есть много примеров. Но есть также примеры в двух репозиториях, так что, может быть, начать с них?

Итак, из-за отсутствия лучших примеров CCTZ, здесь используется пакет R; вы видите входы:

R> library(RcppCCTZ)
R> example(parseDatetime)

prsDttR> ds <- getOption("digits.secs")

prsDttR> options(digits.secs=6) # max value

prsDttR> parseDatetime("2016-12-07 10:11:12",        "%Y-%m-%d %H:%M:%S")   # full seconds
[1] "2016-12-07 10:11:12 UTC"

prsDttR> parseDatetime("2016-12-07 10:11:12.123456", "%Y-%m-%d %H:%M:%E*S") # fractional seconds
[1] "2016-12-07 10:11:12.123456 UTC"

prsDttR> parseDatetime("2016-12-07T10:11:12.123456-00:00")  ## default RFC3339 format
[1] "2016-12-07 10:11:12.123456 UTC"

prsDttR> now <- trunc(Sys.time())

prsDttR> parseDatetime(formatDatetime(now + 0:4))               # vectorised
[1] "2020-05-01 02:16:27 UTC" "2020-05-01 02:16:28 UTC"
[3] "2020-05-01 02:16:29 UTC" "2020-05-01 02:16:30 UTC"
[5] "2020-05-01 02:16:31 UTC"

prsDttR> options(digits.secs=ds)
R> 

Вызывается функция синтаксического анализатора (и игнорируют биты, связанные с R)

Rcpp::DatetimeVector parseDatetime(Rcpp::CharacterVector svec,
                                   std::string fmt = "%Y-%m-%dT%H:%M:%E*S%Ez",
                                   std::string tzstr = "UTC") {
    cctz::time_zone tz;
    load_time_zone(tzstr, &tz);
    sc::system_clock::time_point tp;
    cctz::time_point<cctz::sys_seconds> unix_epoch =
        sc::time_point_cast<cctz::sys_seconds>(sc::system_clock::from_time_t(0));

    // if we wanted a 'start' timer
    //sc::system_clock::time_point start = sc::high_resolution_clock::now();

    auto n = svec.size();
    Rcpp::DatetimeVector dv(n, tzstr.c_str());
    for (auto i=0; i<n; i++) {
        std::string txt(svec(i));

        if (!cctz::parse(fmt, txt, tz, &tp)) Rcpp::stop("Parse error on %s", txt);

        // time since epoch, with fractional seconds added back in
        // only microseconds guaranteed to be present
        double dt = sc::duration_cast<sc::microseconds>(tp - unix_epoch).count() * 1.0e-6;

        // Rcpp::Rcout << "tp: " << cctz::format(fmt, tp, tz) << "\n"
        //             << "unix epoch: " << cctz::format(fmt, unix_epoch, tz) << "\n"
        //             << "(tp - unix.epoch).count(): " << (tp - unix_epoch).count() << "\n"
        //             << "dt: " << dt << std::endl;

        dv(i) = Rcpp::Datetime(dt);
    }

    return dv;
}

Он просматривает входящий вектор svec строк и преобразует каждую из них.

Изменить: Вот еще один пример использования нашего пакета nanotime, который использует и использует Парсер CCTZ:

R> library(nanotime)
R> as.nanotime("2020-01-29 13:12:00.000000001 America/New_York")
[1] 2020-01-29T18:12:00.000000001+00:00
R> 

Полная точность 9 + 9 цифр с использованием базовых наносекунд с эпохи, полная совместимость с std::chrono.

person Dirk Eddelbuettel    schedule 01.05.2020
comment
Нет, ты был слишком быстр для меня. :-) - person Howard Hinnant; 01.05.2020
comment
Ух ты. Такого никогда не было. Спасибо за внимание! - person Dirk Eddelbuettel; 01.05.2020
comment
в коде, который я добавил - работают микросекунды и миллисекунды ... вы можете добавить это к моменту времени. Я не знаю, как создать точку времени с полным date_time, имеющим наносекундное разрешение. Ваш пример выше относится к микро, а не к нано. - person Admiral Kirk; 01.05.2020
comment
Если я правильно помню, разница между доступностью micro и nano оставлена ​​на усмотрение реализации / ОС. Я живу в Linux, и у нас очень есть наносекунды, так как я был соавтором пакета nanotime, который использует (Rcpp) CCTZ (а теперь и (Rcpp) Date), и он очень хорошо передает наносекунды - в наши дни я использую его ежедневно. - person Dirk Eddelbuettel; 01.05.2020
comment
Возможно, вы имеете в виду пример, который я показал, и я, возможно, показал плохой, поскольку он преобразуется в типы времени R по умолчанию, и эти равны микросекундам. Позвольте мне добавить второй. - person Dirk Eddelbuettel; 01.05.2020