2017-05-23 17 views
1

サーバ側(.NETアプリケーションを実行している)からuint64_tの値を標準のC++(WindowsとLinux上で実行する必要がある)で書かれたアプリケーションに取得します。C++である環境から別の環境に時間を変換する

この数値は、Windowsファイル時間を表します(エポックが1601-01-01 00:00:00 UTC以降の100ナノ秒間隔)。

私はアプリケーションの中で時間の文字列表現を返す必要があります。これは正確にナノ秒(正確にはサーバーからの値になります)です。したがって、クロノライブラリを使用する必要があります。

C++の時代は1970年1月1日から1970年1月1日までですから、まず1970年から1601年までのオフセットを計算し、それをサーバーから取得した数値から差し引く必要があります。これを行うには、まず、私がchrono :: time_pointとして取得した値を表現して、1001ナノ秒の間隔でエポック1601-01-01 00:00:00 UTCを計算する必要があります。私は同じ規模になっています。

私はaddjustedTimeFromServerを持っています。これは、サーバーからマイナス(chrono :: time_point形式で)のオフセットを取得した値です。精度で値を抽出するには、std :: time_tに変換する必要があります秒、次にクロノから:: 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; 

(でもすべてのスケール変換の問題の前に)コードが動作しないと私はit.The最初の問題を解決するかどうかはわからないことはmktimeです(& TM:それは私が必要なものを行いません)私に間違った価値を与えます。 tmはC++エポック以前の値を表すので、mktime(& tm)は-1を返します。私は何とかそれを克服する必要があるので、私は.NET Filetimeエポック(1601-01-01 00:00:00 UTC)のtime_pointを計算しなければならないので、それをサーバーから取得する値から減算する必要があります。

私は、この問題と一般的なプログラムのヘルプを歓迎します。私はこのコードで印刷が、最終バージョンでは、私が実際に寄贈されたのと同じ文字列(CTIMEにより与えられる部分(& t)とfractional_secondsにおける一部)

答えて

3

Here is code to do thisの両方の部分を連結します

PSこのサイトには、MSVC std :: libチーム(Billy O'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)}; 
} 

これは、Windows上でLinux上でナノ秒の精度と100ナノ秒の精度を有し、system_clock::time_pointに変換します。

my date/time libraryを使用すると、system_clock::time_pointを任意のフォーマットで完全な精度でフォーマットするのが簡単です。私にとって

#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 

注これが唯一のマイクロ秒の精度であることが

また、ここでは、Windows FILETIME構造を使用せずにです。 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の精度がありますウィンドウの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 
+0

タイプFILETIMEは私の踏査では認識されません。純粋なC++コードを書いているので、私は.NETオブジェクトを持っていません。私は、FILETIMEを表すサーバーのuint64_t値から取得します。このコードでuint64_tを使用する方法はありますか? – primeQuestion

+0

ああ、確かに、ちょっと分かりまして、私は答えを編集します... –

+0

ありがとうたくさん:) – primeQuestion

関連する問題