我正在尝试最近的std::chrono
API,我发现在64位Linux体系结构和GCC编译器上time_point
和duration
类无法处理操作系统的最大时间范围最大分辨率(纳秒(。实际上,与timespec
和timeval
相比,这些类的存储似乎是64位积分类型,它们在内部使用两个64位整数,一个用于秒,一个用于纳米秒:
#include <iostream>
#include <chrono>
#include <typeinfo>
#include <time.h>
using namespace std;
using namespace std::chrono;
int main()
{
cout << sizeof(time_point<nanoseconds>) << endl; // 8
cout << sizeof(time_point<nanoseconds>::duration) << endl; // 8
cout << sizeof(time_point<nanoseconds>::duration::rep) << endl; // 8
cout << typeid(time_point<nanoseconds>::duration::rep).name() << endl; // l
cout << sizeof(struct timespec) << endl; // 16
cout << sizeof(struct timeval) << endl; // 16
return 0;
}
在64位Windows(MSVC2017(上,情况非常相似:存储类型也是64位整数。当处理稳定(又称单调(时钟时,这不是问题,但是存储限制使不同的API实现不适合存储更大的日期和更宽的时间跨度,从而为类似Y2K的错误创造了基础。问题被确认吗?是否有更好的实施或API改进的计划?
这是这样做的,以便您获得最大的灵活性以及紧凑的大小。如果您需要超细精度,则通常不需要非常大的范围。而且,如果您需要很大的范围,通常不需要很高的精度。
例如,如果您正在贩运纳秒,您是否经常考虑/- 292年?而且,如果您需要考虑一个比这更大的范围,那么微秒井会给您/- 292 千年年。
MACOS system_clock
实际上返回微秒,而不是纳秒。从1970年起,时钟可以运行29.2千年。
Windows system_clock
的精度为100 ns单元,因此/- 292千年。
如果数十万年还不够,请尝试毫秒。现在,您的范围为/- 292 百万年。
最后,如果您只有具有纳秒精度超过几百年,则<chrono>
也允许您自定义存储空间:
using dnano = duration<double, nano>;
这使您可以将纳秒存储为double
。如果您的平台支持128位积分类型,则可以使用它:
using big_nano = duration<__int128_t, nano>;
heck,如果您为timespec
编写超载的操作员,甚至可以将使用用于存储(虽然我不建议它(。
您还可以实现比纳秒秒更好的精确度,但是您会牺牲范围。例如:
using picoseconds = duration<int64_t, pico>;
这仅有/- .292年(几个月(。因此,您 do 必须小心。尽管您有一个源时钟可以给您子纳秒精度。
,非常适合时间。查看此视频以获取有关<chrono>
的更多信息。
用于创建,操纵和存储日期的范围大于当前Gregorian日历的有效性,我创建了此开放式日期库,该库将使用日历服务扩展了<chrono>
库。该图书馆将这一年存储在一个签名的16位整数中,因此/- 32K年。可以这样使用:
#include "date.h"
int
main()
{
using namespace std::chrono;
using namespace date;
system_clock::time_point now = sys_days{may/30/2017} + 19h + 40min + 10s;
}
update
在下面的评论中,问如何将 duration<int32_t, nano>
归一化为秒和纳秒(然后将秒添加到time_point(。
首先,我会谨慎地将纳秒塞入32位。该范围只有/- 2秒。但这是我将这样的单位分开的方式:
using ns = duration<int32_t, nano>;
auto n = ns::max();
auto s = duration_cast<seconds>(n);
n -= s;
请注意,仅当n
为正时,这才有效。要正确处理负n
,最好的办法是:
auto n = ns::max();
auto s = floor<seconds>(n);
n -= s;
std::floor
使用C 17引入。如果您愿意的话,可以从这里或这里抓住它。
我是上面的减法操作的部分,因为我发现它更可读。但这也有效(如果n
不是负面(:
auto s = duration_cast<seconds>(n);
n %= 1s;
1s
在C 14中引入。在C 11中,您必须使用seconds{1}
。
有秒(s
(后,您可以将其添加到time_point
。
std::chrono::nanoseconds
是std::chrono::duration<some_t, std::nano>
的类型别名,其中some_t
是一个签名的INT,存储至少64位。这仍然允许纳秒精度至少有292年的范围。
值得注意的是,唯一具有标准特征的积分类型是int
(| _fast
| _least
(64_t
家族。
如果您的实现提供了一个,则可以自由选择更广泛的类型来表示您的时间。您可以免费提供一个命名空间,其中包含一堆typedef的命名空间,这些命名空间以 std::chrono
的比率为单位,而较宽的类型为表示。