我在程序中获得了人类可读的时间戳。我想将它们存储在数据库中,并以不同的方式使用它们。我更愿意将它们表示为长整理,因为它更容易,更有效,但是能够在机器读取的方便和人类的方便之间进行切换也很方便。
我已经将以下测试程序整合在一起,其中包括将人类可读时间戳转换为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
。因此,当将得到的长时间转换回人类可读时间戳时,分数秒信息将丢失。
到目前为止我已经尝试了很多东西,我无法弄清楚millis_from_date函数应该如何工作而不会丢失小数秒信息。任何想法??
答案 0 :(得分:4)
删除long
之前的句号并且有效。请参阅此处的示例:http://www.boost.org/doc/libs/1_60_0/doc/html/date_time/date_time_io.html#time_input_facet_accessors
另请注意,毫秒不足以存储示例long
的整体精度。由于你有6个十进制数字,你需要微秒。
另请注意,自1970年1月1日以来,存在巨大的微秒负载,因此uint64_t
是不够的。最后使用boost
并不是一个好主意,因为这种类型在不同的平台上可能有不同的大小。更好的想法是将$ perl -MO=Concise -e'sort'
5 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
4 <@> sort vK ->5
3 <0> pushmark s ->4
-e syntax OK
用于此目的,sort
用于存储持续时间的内容。在64位的帮助下,您将能够将微秒存储在另外五百万年左右。
答案 1 :(得分:2)
为了防止有人想使用更新的C ++ 11 <chrono>
类型来处理这样的问题,以下是使用此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