簡體   English   中英

納秒和計時 C++

[英]Nanoseconds & Chrono C++

2018-10-01 00:06:16.700000000

我有一個帶有上述時間戳的時間序列數據文件。 我需要將其轉換為從紀元開始的納秒,然后我需要將毫秒、微米或納秒添加到時間戳(移位)。 最后,對於 select 記錄,將其恢復為上述格式。

我在創建時間點時遇到問題 - 以及如何表示納秒......它適用於微秒。

我可以請求一些關於下面的代碼片段的幫助......而且一旦我從紀元獲得納秒 - 我如何 go 回到像上面那樣的時間戳。

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;

}

我在創建時間點時遇到問題 - 以及如何表示納秒......它適用於微秒。

這告訴我您的system_clock::time_point的精度比納秒更粗(在 llvm 上是微秒,在 Windows 上是 1/10 微秒)。 將納秒添加到此類time_point的最簡單方法是:

auto tp = temp_time_point + nanoseconds (nsecs);

這個time_point是一個仍基於system_clock的 time_point,但具有system_clock::durationnanoseconds的“通用類型”的精度,實際上,這只是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粗。

然后使用formattime_point轉換回string

Output:

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

現在我知道現在完全符合 C++20 <chrono>的東西很少見(它即將到來)。 在它出現之前,有一個與 C++11 兼容的C++20 <chrono>預覽庫 它是免費和開源的。 並且只需要很少的句法更改:

#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';
}

Output:

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

您可以將文本直接轉換為納秒級分辨率。 基本上有兩個關鍵庫:

  • 一些谷歌工程師的CCTZ ,雖然(像許多項目一樣)不是正式發布的谷歌產品

  • Howard Hinnant 的日期,他可能會在我完成打字之前在這里回答; 他的庫是 C++20 中內容的基礎

我已經為 R (通過 Rcpp)包裝了兩者,並且有很多例子。 但是這兩個倉庫中也有例子,所以也許從那里開始?

因此,由於缺乏更好的直接 CCTZ 示例,這里是使用 R package 的示例; 你看到輸入:

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> 

調用的解析器 function 是(並忽略 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 package 的另一個示例,它利用並使用 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完全互操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM