考虑格式的历史日期字符串:
Thu Jan 9 12:35:34 2014
我想将这样的字符串解析为某种 C++ 日期表示,然后计算从那时起经过的时间量。
从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。
这可以用新的 C++11std::chrono
命名空间来完成吗?如果没有,我今天应该怎么做?
我正在使用 g++-4.8.1 虽然大概答案应该只针对 C++11 规范。
考虑格式的历史日期字符串:
Thu Jan 9 12:35:34 2014
我想将这样的字符串解析为某种 C++ 日期表示,然后计算从那时起经过的时间量。
从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。
这可以用新的 C++11std::chrono
命名空间来完成吗?如果没有,我今天应该怎么做?
我正在使用 g++-4.8.1 虽然大概答案应该只针对 C++11 规范。
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));
版本 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));
老问题的新答案。新答案的理由:该问题是从其原始形式编辑的,因为当时的工具无法准确处理所询问的内容。由此产生的接受答案给出的行为与原始问题所要求的行为略有不同。
我不是要放弃接受的答案。这是一个很好的答案。只是C API实在是太混乱了,难免会出现这样的错误。
最初的问题是解析"Thu, 9 Jan 2014 12:35:34 +0000"
. 很明显,目的是解析代表 UTC 时间的时间戳。但是strptime
(它不是标准的 C 或 C++,而是 POSIX)不解析尾随的 UTC 偏移量,表明这是一个 UTC 时间戳(它将用 格式化它%z
,但不解析它)。
然后编辑该问题以询问有关"Thu Jan 9 12:35:34 2014"
. 但是没有编辑问题以澄清这是 UTC 时间戳,还是计算机当前本地时区中的时间戳。接受的答案隐含地假设时间戳代表计算机的当前本地时区,因为使用了std::mktime
.
std::mktime
不仅将字段类型tm
转换为串行类型time_t
,它还执行从计算机本地时区到 UTC 的偏移调整。
但是,如果我们想将 UTC 时间戳解析为原始(未经编辑的)问题,该怎么办?
今天可以使用这个更新的、免费的开源库来完成。
#include "date/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);
}
这个库可以解析%z
. 并且date::sys_seconds
只是一个 typedef 用于:
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
问题还问:
从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。
那部分仍未得到答复。这是您使用此库的方法。
#include "date/date.h"
#include <chrono>
#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 = hh_mm_ss<seconds>{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>
将 seconds-precision 截断为time_point
days -precision time_point
。如果从 中减去天数精度time_point
,则tp
剩下的 aduration
表示自午夜 (UTC) 以来的时间。
该类型hh_mm_ss<seconds>
采用任何duration
可转换为seconds
(在本例中为从午夜开始的时间),并为每个字段创建一个{hours, minutes, seconds}
带有 getter 的字段类型。如果持续时间的精度小于秒,则此字段类型还将具有亚秒的吸气剂。在 C++17 之前,必须将更精细的持续时间指定为模板参数。在 C++17 及更高版本中,可以推导出:
auto hms = hh_mm_ss{tp - tp_days};
最后,可以打印出所有这些持续时间。此示例输出:
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
所以 2014-01-09 是 1970-01-01 之后的 16079 天。
这是完整的示例,但很milliseconds
精确:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34.123 +0000"};
sys_time<milliseconds> tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
hh_mm_ss hms{tp - tp_days};
std::cout << tp << '\n';
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';
std::cout << "Number of milliseconds = " << hms.subseconds() << '\n';
}
输出:
2014-01-09 12:35:34.123
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
Number of milliseconds = 123ms
这个库现在是 C++20 的一部分,但在namespace std::chrono
header 中找到<chrono>
。
这是相当 C-ish 并且不像 Simple 的答案那样优雅的解决方案,但我认为它可能有效。这个答案可能是错误的,但我会保留它,以便有人可以发布更正。
#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;
}
涵盖的案例(代码如下):
从给定日期到现在
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;
完整代码:
#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;
}
} // ()