如何将日期字符串解析为 c++11 std::chrono time_point 或类似的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21021388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to parse a date string into a c++11 std::chrono time_point or similar?
提问by Drew Noakes
Consider a historic date string of format:
考虑格式的历史日期字符串:
Thu Jan 9 12:35:34 2014
I want to parse such a string into some kind of C++ date representation, then calculate the amount of time that has passed since then.
我想将这样的字符串解析为某种 C++ 日期表示形式,然后计算从那时起经过的时间量。
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。
Can this be done with the new C++11 std::chrono
namespace? If not, how should I go about this today?
这可以用新的 C++11std::chrono
命名空间完成吗?如果没有,我今天应该怎么做?
I'm using g++-4.8.1 though presumably an answer should just target the C++11 spec.
我正在使用 g++-4.8.1,但大概答案应该只针对 C++11 规范。
回答by Simple
std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
GCC prior to version 5 doesn't implement std::get_time
. You should also be able to write:
版本 5 之前的 GCC 没有实现std::get_time
. 您还应该能够编写:
std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
回答by Howard Hinnant
New answer for old question. Rationale for the new answer: The question was edited from its original form because tools at the time would not handle exactly what was being asked. And the resulting accepted answer gives a subtly different behavior than what the original question asked for.
旧问题的新答案。新答案的基本原理:该问题已从其原始形式进行了编辑,因为当时的工具无法准确处理所提出的问题。结果接受的答案给出了与原始问题所要求的略有不同的行为。
I'm not trying to put down the accepted answer. It's a good answer. It's just that the C API is soconfusing that it is inevitable that mistakes like this will happen.
我不是要放下已接受的答案。这是一个很好的答案。只是C API太混乱了,难免会出现这样的错误。
The original question was to parse "Thu, 9 Jan 2014 12:35:34 +0000"
. So clearly the intent was to parse a timestamp representing a UTC time. But strptime
(which isn't standard C or C++, but is POSIX) does not parse the trailing UTC offset indicating this is a UTC timestamp (it will format it with %z
, but not parse it).
最初的问题是解析"Thu, 9 Jan 2014 12:35:34 +0000"
. 很明显,目的是解析代表 UTC 时间的时间戳。但是strptime
(这不是标准的 C 或 C++,而是 POSIX)不解析尾随的 UTC 偏移量,表明这是一个 UTC 时间戳(它将用 格式化%z
,但不解析它)。
The question was then edited to ask about "Thu Jan 9 12:35:34 2014"
. But the question was notedited to clarify if this was a UTC timestamp, or a timestamp in the computer's current localtimezone. The accepted answer implicitlyassumes the timestamp represents the computer's current local timezone because of the use of std::mktime
.
然后对该问题进行编辑以询问有关"Thu Jan 9 12:35:34 2014"
. 但是没有编辑问题以澄清这是 UTC 时间戳,还是计算机当前本地时区的时间戳。接受的答案隐含假定时间戳表示因为使用的计算机的当前本地时区std::mktime
。
std::mktime
not only transforms the field type tm
to the serial type time_t
, it also performs an offset adjustment from the computer's local time zone to UTC.
std::mktime
不仅将字段类型tm
转换为串行类型time_t
,它还执行从计算机本地时区到 UTC 的偏移调整。
But what if we want to parse a UTC timestamp as the original (unedited) question asked?
但是,如果我们想按照原始(未经编辑)的问题来解析 UTC 时间戳怎么办?
That can be done today using this newer, free open-source library.
今天可以使用这个更新的免费开源库来完成。
#include "date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
}
This library canparse %z
. And date::sys_seconds
is just a typedef for:
这个库可以解析%z
. 并且date::sys_seconds
只是一个 typedef:
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
The question also asks:
问题还问:
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。
That part has remained unanswered. Here's how you do it with this library. For this part I'm also going to use a second header-only library "chrono_io.h"
:
这部分仍未得到答复。以下是您如何使用此库进行操作。对于这一部分,我还将使用第二个仅标头库"chrono_io.h"
:
#include "chrono_io.h"
#include "date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
auto hms = make_time(tp - tp_days);
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
}
floor<days>
truncates the seconds-precision time_point
to a days-precisiontime_point
. If you subtract the days-precision time_point
from tp
, you're left with a duration
that represents the time since midnight (UTC).
floor<days>
将 seconds-precision 截断time_point
为days-precisiontime_point
。如果减去天精密time_point
的tp
,你留下了一个duration
表示自午夜(UTC)时间。
The factory function make_time
takes any duration
(in this case time since midnight) and creates a {hours, minutes, seconds}
field type with getters for each field. If the duration has precision finer than seconds this field type will also have a getter for the subseconds.
factory 函数make_time
采用 any duration
(在本例中为午夜之后的时间)并{hours, minutes, seconds}
为每个字段创建一个带有 getter的字段类型。如果持续时间的精度比秒更精细,则此字段类型还将具有亚秒的 getter。
Finally, using "chrono_io.h"
, one can just print out all of these durations. This example outputs:
最后,使用"chrono_io.h"
,可以打印出所有这些持续时间。此示例输出:
Number of days = 16079[86400]s
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
The [86400]s
represents the units of the duration
that has days-precision. So 2014-01-09 is 16079 days after 1970-01-01.
该[86400]s
代表的单位duration
有天精度。所以 2014-01-09 是 1970-01-01 之后的 16079 天。
回答by Howard Hinnant
This is rather C-ish and not as elegant of a solution as Simple's answer, but I think it might work. This answer is probably wrong but I'll leave it up so someone can post corrections.
这是相当C-ish,不像Simple's answer那样优雅的解决方案,但我认为它可能有效。这个答案可能是错误的,但我会留下它,以便有人可以发表更正。
#include <iostream>
#include <ctime>
int main ()
{
struct tm timeinfo;
std::string buffer = "Thu, 9 Jan 2014 12:35:00";
if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
std::cout << "Error.";
time_t now;
struct tm timeinfo2;
time(&now);
timeinfo2 = *gmtime(&now);
time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
time(&seconds);
struct tm result;
result = *gmtime ( &seconds );
std::cout << result.tm_sec << " " << result.tm_min << " "
<< result.tm_hour << " " << result.tm_mday;
return 0;
}
回答by cibercitizen1
Cases covered (code is below):
涵盖的案例(代码如下):
since a give date until now
long int min0 = getMinutesSince( "2005-02-19 12:35:00" );
since the epoch until now
long int min1 = getMinutesSince1970( );
between two date+hours (since the epoch until a given date)
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
cout << min1 - min0 << endl;
从一个给定日期到现在
long int min0 = getMinutesSince( "2005-02-19 12:35:00" );
从古至今
long int min1 = getMinutesSince1970( );
两个日期+小时之间(从纪元到给定日期)
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
cout << min1 - min0 << endl;
Complete code:
完整代码:
#include <iostream>
#include <chrono>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970Until( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(mktime(&tm));
return
chrono::duration_cast<chrono::minutes>(
tp.time_since_epoch()).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970() {
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>( now.time_since_epoch() ).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point then =
chrono::system_clock::from_time_t(mktime(&tm));
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>(
now.time_since_epoch()-
then.time_since_epoch()
).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
int main () {
long int min = getMinutesSince1970Until( "1970-01-01 01:01:00" );
cout << min << endl;
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
if ( (min1 - min0) != 4 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
min0 = getMinutesSince( "1970-01-01 01:00:00" );
min1 = getMinutesSince1970( );
if ( (min1 - min0) != 0 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
} // ()