2016-04-24 5 views
3

私のプログラムに人間が読めるタイムスタンプがあります。私はそれらをデータベースに保存し、それらをさまざまな方法で使用したいと考えています。私はそれをより簡単でより効率的なものとして表現することを好むでしょうが、読み込みに便利なものと人間には便利なものの間を転がることができるのも便利です。情報を失うことなく、人間が読める日付をミリ秒に変換して返します。

私は、人が読めるタイムスタンプをlongとbackに変換したり、戻したりする関数を含む、以下のテストプログラムをハッキングしました。

// g++ -o timetest timetest.cpp -std=c++11 

#include <iostream> 
#include <sstream> 

#include <boost/date_time.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 

long millis_from_date(const std::string& s) 
{ 
    boost::posix_time::ptime pt; 
    std::istringstream is(s); 
    auto* f = new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%S.%FZ"); 
    std::locale loc(std::locale(""), f); 
    is.imbue(loc); 
    is >> pt; 
    boost::posix_time::ptime timet_start(boost::gregorian::date(1970,1,1)); 
    boost::posix_time::time_duration diff = pt - timet_start; 
    return diff.total_milliseconds(); 
} 

std::string date_from_millis(long ms) 
{ 
    static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); 
    boost::posix_time::time_facet * facet = new boost::posix_time::time_facet("%Y-%m-%dT%H:%M:%S.%fZ"); 
    std::ostringstream stream; 
    stream.imbue(std::locale(stream.getloc(), facet)); 
    stream << epoch + boost::posix_time::milliseconds(ms);; 
    return stream.str(); 
} 

int main() 
{ 
    std::string time = "2016-04-14T07:47:50.120043Z"; 

    std::cout << "Initial input:   " << time << std::endl; 
    std::cout << std::endl; 

    { 
    long millis = millis_from_date(time); 
    std::cout << "Initial input in millis: " << millis << std::endl; 

    std::string newtime = date_from_millis(millis); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 

    { 
    long millis = millis_from_date(time); 
    std::cout << "Initial input in millis: " << millis << std::endl; 

    std::string newtime = date_from_millis(millis); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 

    return 0; 
} 

次はサンプル出力です。あなたが見ることができるように

Initial input:   2016-04-14T07:47:50.120043Z 

Initial input in millis: 1460620070000 
Converted back to date: 2016-04-14T07:47:50.000000Z 
Initial input in millis: 1460620070000 
Converted back to date: 2016-04-14T07:47:50.000000Z 

、ミリ秒に変換し、小数第二の情報は何を得ることは端にタック000でエポックの開始からの秒であるので失われます。従って、得られた長い時間を人間可読のタイムスタンプに変換すると、小数第2情報は失われる。

これまでにかなり多くのことを試みましたが、millis_from_date関数が分数秒の情報を失うことなく動作する方法を理解できません。何か案は??

答えて

4

%Fより前の期間を削除しても機能します。ここでの例を参照してください。http://www.boost.org/doc/libs/1_60_0/doc/html/date_time/date_time_io.html#time_input_facet_accessors

例:2016-04-14T07:47:50.120043Zの精度全体を格納するには、ミリ秒では不十分です。 10進数が6桁であるため、マイクロ秒が必要です。

また、longで十分ではないため、1970年1月1日以降のマイクロ秒の膨大な負荷があることにも注意してください。とにかくlongを使うのは良い考えではありません。なぜなら、このタイプはプラットフォームによって異なるかもしれないからです。この目的のためにuint64_tを使用することをお勧めします。それはboostが時間の長さを保存するために使用しているものです。 64ビットの助けを借りれば、別の50万年の間マイクロ秒を保存することができます。誰かがここでは、新しいC++ 11の<chrono>タイプを使用して、このような問題を動作するようにしたいと思い念の

+0

はあなたにミハイルをありがとう、私はあなたのアドバイスに従い、今ではすべてが正確にそれが必要として動作します。 – user6247858

+0

@ user6247858あなたはようこそ! – Mikhail

2

あなたは小数秒のフォーマットと解析を支援するために、このfree open source libraryを使用してそれを行うことができる方法である:

出力
#include "tz.h" 
#include <iostream> 

std::chrono::milliseconds 
millis_from_date(const std::string& s) 
{ 
    using namespace std::chrono; 
    using sys_milliseconds = time_point<system_clock, milliseconds>; 
    sys_milliseconds pt; 
    std::istringstream is(s); 
    date::parse(is, "%FT%TZ", pt); 
    return pt.time_since_epoch(); 
} 

std::string 
date_from_millis(std::chrono::milliseconds ms) 
{ 
    using namespace std::chrono; 
    using sys_milliseconds = time_point<system_clock, milliseconds>; 
    return date::format("%FT%TZ", sys_milliseconds{ms}); 
} 

int 
main() 
{ 
    std::string time = "2016-04-14T07:47:50.120043Z"; 

    std::cout << "Initial input:   " << time << std::endl; 
    std::cout << std::endl; 

    { 
    auto millis = millis_from_date(time); 
    std::cout << "Initial input in millis: " << millis.count() << std::endl; 

    std::string newtime = date_from_millis(millis); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 

    { 
    auto millis = millis_from_date(time); 
    std::cout << "Initial input in millis: " << millis.count() << std::endl; 

    std::string newtime = date_from_millis(millis); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 
} 

Initial input:   2016-04-14T07:47:50.120043Z 

Initial input in millis: 1460620070120 
Converted back to date: 2016-04-14T07:47:50.120Z 
Initial input in millis: 1460620070120 
Converted back to date: 2016-04-14T07:47:50.120Z 

を私たちは本当にここにロスレスになりたい場合は、Mikhail's excellent answerで述べたように、我々はマイクロ秒の代わりにミリ秒単位のトラフィックに必要です。ここでは、上記のコードはそれを行うように変更される方法である:

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

std::chrono::microseconds 
micros_from_date(const std::string& s) 
{ 
    using namespace std::chrono; 
    using sys_microseconds = time_point<system_clock, microseconds>; 
    sys_microseconds pt; 
    std::istringstream is(s); 
    date::parse(is, "%FT%TZ", pt); 
    return pt.time_since_epoch(); 
} 

std::string 
date_from_micros(std::chrono::microseconds ms) 
{ 
    using namespace std::chrono; 
    using sys_microseconds = time_point<system_clock, microseconds>; 
    return date::format("%FT%TZ", sys_microseconds{ms}); 
} 

int 
main() 
{ 
    std::string time = "2016-04-14T07:47:50.120043Z"; 

    std::cout << "Initial input:   " << time << std::endl; 
    std::cout << std::endl; 

    { 
    auto micros = micros_from_date(time); 
    std::cout << "Initial input in micros: " << micros.count() << std::endl; 

    std::string newtime = date_from_micros(micros); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 

    { 
    auto micros = micros_from_date(time); 
    std::cout << "Initial input in micros: " << micros.count() << std::endl; 

    std::string newtime = date_from_micros(micros); 
    std::cout << "Converted back to date: " << newtime << std::endl; 
    } 
} 

出力する:

Initial input:   2016-04-14T07:47:50.120043Z 

Initial input in micros: 1460620070120043 
Converted back to date: 2016-04-14T07:47:50.120043Z 
Initial input in micros: 1460620070120043 
Converted back to date: 2016-04-14T07:47:50.120043Z 
関連する問題