我从服务器端(运行.NET应用程序)获取uint64_t值到我的应用程序中,该应用程序是用标准C ++编写的(必须在Windows和Linux上运行)。
此数字代表Windows Filetime - 自纪元以来的100纳秒间隔,即1601-01-01 00:00:00 UTC。
我需要在我的应用程序中返回时间的字符串表示,精确度为纳秒(这是我从服务器获取的值的准确度)所以我必须使用时间库。
由于C ++的纪元是0001年1月1日到1970年1月1日,我首先需要计算从1970到1601的偏移量,并从我从服务器得到的数字中减去它。为了做到这一点,我首先必须将我从服务器获得的值表示为chrono :: time_point,并以100纳秒的间隔比例计算纪元1601-01-01 00:00:00 UTC,以便它和值我得到了相同的规模。
我有addjustedTimeFromServer - 这是我从服务器获得的值减去(在chrono :: time_point表单中)偏移量,我需要将其转换为std :: time_t,以便提取精度为秒,然后从chrono :: time_point我需要提取fractional_seconds,这将给我精确的纳秒,我将它们连接到代表时间的字符串。
这是我的代码。它不能满足我的需要:
using FileTime = duration<int64_t, ratio<1, 10000000>>;
struct std::tm tm;
//create time point for epoch of Windows Filetime (1601-01-01 00:00:00 UTC))
std::istringstream ss("1601-01-01 00:00:00");
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
std::time_t tt = mktime(&tm);
std::chrono::system_clock::time_point offset =std::chrono::system_clock::from_time_t(tt);
//convert the offset into 100-nanosecond intervals scale
auto offset_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(offset);
auto offset_100ns = FileTime(offset_ns.time_since_epoch());
//substract the offset from i so now it starts from 1970 like the epoch of C++
auto iDuration = FileTime(static_cast<int64_t>(i));
//auto iDuration_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(iDuration); //doesn't compile - but that's the idea of what i want to do in this line
std::chrono::system_clock::time_point adjustedTime = iDuration/*iDuration_ns*/ - offset /*-offset_100ns*/; //the commented out parts are what i think is the correct thing to do (scale wise) but they don't compile
//convert the time_point into the string representation i need (extract the regular time, up to seconds, with time_t and the nanosecond part with ns.count())
nanoseconds ns = duration_cast<nanoseconds>(adjustedTime.time_since_epoch());
seconds s = duration_cast<seconds>(ns);
std::time_t t = s.count();
std::size_t fractional_seconds = ns.count() % 10000000;
std::cout << std::ctime(&t) << std::endl;
std::cout << fractional_seconds << std::endl;
代码不起作用,我不知道如何解决它。第一个问题(甚至在所有规模转换问题之前)是mktime(&amp; tm)给了我一个不正确的值。由于tm表示在C ++纪元之前的值,因此mktime(&amp; tm)返回-1。我需要以某种方式克服它,因为我必须计算.NET Filetime纪元(1601-01-01 00:00:00 UTC)的time_point,以便从我从服务器获得的值中减去它。
我将在这个问题以及整个计划中提供帮助。
P.S我只是在这段代码中打印,但在最终版本中,我将两个部分连接到相同的字符串(ctime(&amp; t)给出的部分和fractional_seconds中的部分)
答案 0 :(得分:4)
Here is code to do this实际上由MSVC std :: lib团队成员(Billy O&#39; Neal)捐赠给了这个网站。
在此重复:
// filetime_duration has the same layout as FILETIME; 100ns intervals
using filetime_duration = duration<int64_t, ratio<1, 10'000'000>>;
// January 1, 1601 (NT epoch) - January 1, 1970 (Unix epoch):
constexpr duration<int64_t> nt_to_unix_epoch{INT64_C(-11644473600)};
system_clock::time_point
FILETIME_to_system_clock(FILETIME fileTime)
{
const filetime_duration asDuration{static_cast<int64_t>(
(static_cast<uint64_t>(fileTime.dwHighDateTime) << 32)
| fileTime.dwLowDateTime)};
const auto withUnixEpoch = asDuration + nt_to_unix_epoch;
return system_clock::time_point{
duration_cast<system_clock::duration>(withUnixEpoch)};
}
这将转换为system_clock::time_point
,它在Linux上具有纳秒精度,在Windows上具有100纳秒精度。
使用my date/time library,您可以轻松地将system_clock::time_point
格式化为您想要的任何格式的全精度。
此外,这里没有使用Windows FILETIME
结构:
#include "date.h"
#include <string>
#include <iostream>
std::chrono::system_clock::time_point
FILETIME_to_system_clock(std::uint64_t fileTime)
{
using namespace std;
using namespace std::chrono;
// filetime_duration has the same layout as FILETIME; 100ns intervals
using filetime_duration =duration<int64_t, ratio<1, 10000000>>;
// January 1, 1601 (NT epoch) - January 1, 1970 (Unix epoch):
constexpr duration<int64_t> nt_to_unix_epoch{INT64_C(-11644473600)};
const filetime_duration asDuration{static_cast<int64_t>(fileTime)};
const auto withUnixEpoch = asDuration + nt_to_unix_epoch;
return system_clock::time_point{
duration_cast<system_clock::duration>(withUnixEpoch)};
}
int
main()
{
std::string s = date::format("%F %T", FILETIME_to_system_clock(131400356659154460));
std::cout << s << '\n';
}
这只是我的输出:
2017-05-23 17:54:25.915446
请注意,这只是微秒的精度。在Linux上,这将格式化为纳秒精度,因为system_clock::time_point
在该平台上具有纳秒精度。
如果不是这样的话,你可以这样强制纳秒精度:
using namespace std::chrono;
std::string s = date::format("%F %T",
time_point_cast<nanoseconds>(FILETIME_to_system_clock(131400356659154460)));
为我输出:
2017-05-23 17:54:25.915446000
在此更新中,输出chrono::time_point
的精度与Window的FILETIME:100-ns精度相同:
#include "date.h"
#include <string>
#include <iostream>
using filetime_duration = std::chrono::duration<std::int64_t, std::ratio<1, 10000000>>;
using FileTime = std::chrono::time_point<std::chrono::system_clock, filetime_duration>;
// or more simply:
// using FileTime = date::sys_time<filetime_duration>;
FileTime
FILETIME_to_system_clock(std::uint64_t fileTime)
{
using namespace std;
using namespace std::chrono;
// filetime_duration has the same layout as FILETIME; 100ns intervals
// January 1, 1601 (NT epoch) - January 1, 1970 (Unix epoch):
constexpr seconds nt_to_unix_epoch{-11644473600};
const filetime_duration asDuration{static_cast<int64_t>(fileTime)};
return FileTime{asDuration + nt_to_unix_epoch};
}
int
main()
{
using namespace std::chrono;
std::string s = date::format("%F %T", FILETIME_to_system_clock(131400356659154461));
std::cout << s << '\n';
}
输出:
2017-05-23 17:54:25.9154461