如何解析等效於任何類型的常規DateTime結構的字符串RFC 3339?日期時間格式用於Atom Syndication Format等多種規格。如何使用pa ++解析日期時間並將其轉換爲RFC 3339?
這裏是例子的ATOM日期時間(RFC 3339)格式:
2005-08-15T15:52:01+04:00
如何解析等效於任何類型的常規DateTime結構的字符串RFC 3339?日期時間格式用於Atom Syndication Format等多種規格。如何使用pa ++解析日期時間並將其轉換爲RFC 3339?
這裏是例子的ATOM日期時間(RFC 3339)格式:
2005-08-15T15:52:01+04:00
這裏是libc中的最新版本中一個完整的,但不幸的是不能令人滿意的,然而移植程序++,的libstdC++,VS實現,它以您顯示的格式將字符串解析爲std::chrono::system_clock::time_point
。我找不到DateTime
你引用。但是std::chrono::system_clock::time_point
是一個「DateTime」結構。 std::chrono::system_clock::time_point
是一些持續時間(秒,微秒,納秒,無論)的計數,因爲某些未指定的時期。你可以查詢std::chrono::system_clock::time_point
找出它的持續時間。事實證明,自1970年以來每項實施措施都忽略了閏秒。
#include <chrono>
#include <iostream>
#include <limits>
#include <locale>
#include <sstream>
template <class Int>
// constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<Int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
y -= m <= 2;
const Int era = (y >= 0 ? y : y-399)/400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365]
const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]
return era * 146097 + static_cast<Int>(doe) - 719468;
}
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
namespace std
{
namespace chrono
{
template<class charT, class traits>
std::basic_istream<charT,traits>&
operator >>(std::basic_istream<charT,traits>& is, system_clock::time_point& item)
{
typename std::basic_istream<charT,traits>::sentry ok(is);
if (ok)
{
std::ios_base::iostate err = std::ios_base::goodbit;
try
{
const std::time_get<charT>& tg = std::use_facet<std::time_get<charT> >
(is.getloc());
std::tm t = {};
const charT pattern[] = "%Y-%m-%dT%H:%M:%S";
tg.get(is, 0, is, err, &t, begin(pattern), end(pattern)-1);
if (err == std::ios_base::goodbit)
{
charT sign = {};
is.get(sign);
err = is.rdstate();
if (err == std::ios_base::goodbit)
{
if (sign == charT('+') || sign == charT('-'))
{
std::tm t2 = {};
const charT pattern2[] = "%H:%M";
tg.get(is, 0, is, err, &t2, begin(pattern2), end(pattern2)-1);
if (!(err & std::ios_base::failbit))
{
auto offset = (sign == charT('+') ? 1 : -1) *
(hours{t2.tm_hour} + minutes{t2.tm_min});
item = system_clock::time_point{
days{days_from_civil(t.tm_year+1900, t.tm_mon+1,
t.tm_mday)} +
hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec} -
offset};
}
else
{
err |= ios_base::failbit;
}
}
else
{
err |= ios_base::failbit;
}
}
else
{
err |= ios_base::failbit;
}
}
else
{
err |= ios_base::failbit;
}
}
catch (...)
{
err |= std::ios_base::badbit | std::ios_base::failbit;
}
is.setstate(err);
}
return is;
}
} // namespace chrono
} // namespace std
int
main()
{
std::istringstream infile("2005-08-15T15:52:01+04:00");
std::chrono::system_clock::time_point tp;
infile >> tp;
std::cout << tp.time_since_epoch().count() << '\n';
}
這已經針對libc的測試++,的libstdC++ - 5.0和VS-2015和分別產生:
1124106721000000
1124106721000000000
11241067210000000
在的libC++這是因爲新的年份1970微秒的計數,忽略閏秒。在libstdC++ - 5.0上它是一個納秒計數,在VS-2015上它是一個100納秒的計數。
該解決方案的問題在於它涉及到將函數插入std命名空間。將來,C++委員會可能會決定將相同的函數插入到可能導致代碼無效的相同名稱空間中。
這段代碼的另一個問題是它非常複雜。這個標準並不能提供更簡單的解決方案,這真是令人遺憾。
此代碼的另一個問題是它不使用C標準中記錄的更簡單的「%F」,「%T」和「%z」解析模式(雖然記錄爲格式模式)。我通過實驗發現他們的使用不便攜。
此代碼的另一個問題是它需要gcc-5.0。如果你正在運行gcc-4.9,那你的運氣不好。你必須自己解析。我無法在VS-2015之前測試VS實現。 libC++應該沒問題(即使libC++也不支持「%z」)。
如果需要,您可以通過formulas here將std::chrono::system_clock::time_point
轉換回「分解」結構。但是,如果這是您的最終目標,那麼修改上面的代碼以直接解析您的「分解」結構而不是std::chrono::system_clock::time_point
會更有效。
免責聲明:只有非常輕微的測試。我很高興用任何錯誤報告來更新這個答案。
更新
在,因爲我第一次給了這個答案我已經寫了這確實上面一個更爲簡潔的語法所有的計算庫的年。
#include "chrono_io.h"
#include "date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
std::istringstream infile{"2005-08-15T15:52:01+04:00"};
sys_seconds tp; // This is a system_clock time_point with seconds precision
infile >> parse("%FT%T%Ez", tp);
std::cout << tp.time_since_epoch() << " is " << tp << '\n';
}
你可以找到"chrono_io.h"
和"date.h"
here。他們是免費的,開源的,只有頭文件的庫。在this link也有鏈接full documentation和"date.h"
甚至video tutorial。雖然video tutorial是在執行parse
函數之前創建的。
上述程序的輸出是:
1124106721s is 2005-08-15 11:52:01
其給出既因爲曆元秒(00:00:00 1970-01-01 UTC),並在UTC的日期/時間(取抵消帳戶)。
如果您需要計算自該時代以來的閏秒,此相同GitHub鏈接上的another library可用,但不是僅標題,需要少量installation。但使用它上面的程序的簡單修改:
#include "chrono_io.h"
#include "tz.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
std::istringstream infile{"2005-08-15T15:52:01+04:00"};
utc_seconds tp; // This is a utc_clock time_point with seconds precision
infile >> parse("%FT%T%Ez", tp);
std::cout << tp.time_since_epoch() << " is " << tp << '\n';
}
並且輸出是現在:
1124106743s is 2005-08-15 11:52:01
在代碼的區別在於"tz.h"
現在包含代替"date.h"
,和utc_seconds
被解析而不是sys_seconds
。 utc_seconds
仍然是std::chrono::time_point
,但現在基於閏秒感知時鐘。該程序輸出相同的日期/時間,但自紀元以來秒數現在增加了22秒,因爲這是在1970-01-01和2005-08-15之間插入的閏秒數。