如何制作通用精度ISO时间戳生成器

时间:2017-04-28 15:17:40

标签: c++ c++11 time chrono

我正在编写一个以ISO格式返回当前时间的实用程序函数。但是,我希望能够指定精度:

2017-04-28T15:07:37Z        //s
2017-04-28T15:07:37.035Z    //ms
2017-04-28T15:07:37.035332Z //us

我有工作代码来执行此操作,但是,我似乎无法找到使其通用的方法:

string getISOCurrentTimestamp_us()
{
    char iso_buf[30];

    auto now = chrono::high_resolution_clock::now();
    auto s = chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
    time_t seconds = (time_t) s.count();
    strftime(iso_buf, sizeof(iso_buf), "%FT%T", gmtime(&seconds));

    string iso_timestamp(iso_buf);

    auto us = chrono::duration_cast<chrono::microseconds>(now.time_since_epoch());
    auto us_diff = us - chrono::duration_cast<chrono::microseconds>(s);
    char buffer[8];
    std::snprintf(buffer, sizeof(buffer), ".%06d", (int) us_diff.count());

    iso_timestamp += string(buffer);
    iso_timestamp += "Z";

    return iso_timestamp;
}

如您所见,这个只返回微秒版本。我有一个单独的函数使用chrono:milliseconds作为毫秒版本。当唯一的区别是持续时间模板参数和零填充时,似乎DRY违规具有如此多的类似代码。

然而,能够指定持续时间是棘手的。我想我不太了解函数模板,因为我尝试了类似getISOCurrentTimestamp<chrono::microseconds>()的东西,但无济于事:

template <class T>
string getISOCurrentTimestamp() {
    ...
    auto t = chrono::duration_cast<T>(now.time_since_epoch());
    auto t_diff = t - chrono::duration_cast<T>(s);
}

另一个问题是推断基于T的零填充量,这似乎也不是微不足道的(即微秒应该零填充到6,毫秒到3,等等。

如何使这个ISO字符串函数通用?我是以错误的方式接近这个吗?

编辑:使用@ HowardHinnant的库,我能够编写一个通用的包装器:

template <class Precision>
string getISOCurrentTimestamp()
{
    auto now = chrono::system_clock::now();
    return date::format("%FT%TZ", date::floor<Precision>(now));
}

使用:

调用

string timestamp = getISOCurrentTimestamp<chrono::seconds>()

1 个答案:

答案 0 :(得分:3)

free, open-source, header-only library通过调整输入chrono::time_point函数的format的精度来实现此目的。随意检查代码,看看如何完成。我认为您对decimal_format_seconds特别感兴趣,{{3}}负责计算输出的小数位数(如果有的话)。或者随意使用此代码。

以下是使用它的内容:

#include "date.h"
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    using namespace date;
    system_clock::time_point now = sys_days{2017_y/04/28} + 15h + 7min + 37s + 35332us;
    cout << format("%FT%TZ\n", floor<seconds>(now));
    cout << format("%FT%TZ\n", floor<milliseconds>(now));
    cout << format("%FT%TZ\n", floor<microseconds>(now));
}

输出:

2017-04-28T15:07:37Z
2017-04-28T15:07:37.035Z
2017-04-28T15:07:37.035332Z