2014-01-09 3 views
30

Рассмотрим историческую строку даты в формате:Как разбирать строку даты в C++ 11 std :: chrono time_point или аналогично?

Thu Jan 9 12:35:34 2014 

Я хочу, чтобы разобрать такую ​​строку в какой-то ++ дата представления C, а затем рассчитать количество времени, которое прошло с тех пор.

Из полученной продолжительности мне нужен доступ к номерам секунд, минут, часов и дней.

Можно ли это сделать с помощью нового пространства имен C++ 11 std::chrono? Если нет, то как мне это сделать сегодня?

Я использую g ++ - 4.8.1, хотя предположительно ответ должен быть нацелен только на спецификацию C++ 11.

+3

POSIX-системы (например, Linux или OSX) имеют ['strptime'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html), который анализирует строку в структуре' tm'. К сожалению, он не существует для Windows, но [есть альтернативы] (http://stackoverflow.com/a/321877/440558). –

+0

@JoachimPileborg Поддерживает ли он '+ 0000' в конце? –

+0

@remyabel, на самом деле я ошибся. Этот суффикс не существует. Я обновил вопрос. –

ответ

52
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 до версии 5 не реализует 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)); 
+0

Но * get_time() * еще не реализован на gcc? – SChepurin

+0

@ Щепурин, хм, да 'get_time' не разрешается при g ++. –

+0

@ Щепурин это может и не быть, но это в спецификации C++. – Simple

2

Это довольно C-иш, а не как элегантный ответа решение, как простой, но я думаю, что это могло бы работать. Этот ответ, вероятно, неверен, но я оставлю его, поэтому кто-то может внести исправления.

#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; 
} 
5

Новый ответ для старого вопроса. Обоснование нового ответа: вопрос был отредактирован из его первоначальной формы, потому что инструменты в то время не обрабатывали точно то, что было задано. И полученный принятый ответ дает тонко другое поведение, чем то, что задавал первоначальный вопрос.

Я не пытаюсь принять принятый ответ. Это хороший ответ. Это просто, что 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 в качестве исходного (неотредактированного) вопроса?

Это можно сделать сегодня, используя этот новый, 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); 
} 

Эта библиотека может разобрать %z. И date::sys_seconds просто ЬурейиЙ для:

std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> 

вопрос также спрашивает:

Из полученного срока мне нужен доступ к номерам секунд, минут, часов и дней.

Эта часть осталась без ответа. Вот как вы это делаете с this library. В этой части я также буду использовать вторую header-only library "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> обрежет секундную точность time_point до дней точностиtime_point. Если вы вычтите предел дня time_point из tp, вы останетесь с duration, который представляет время с полуночи (UTC).

Заводская функция make_time принимает любые duration (в данном случае время с полуночи) и создает полевой тип {hours, minutes, seconds} с геттерами для каждого поля. Если продолжительность имеет точность мельче, чем секунды, этот тип поля также будет иметь геттер для субсекунд.

Наконец, используя "chrono_io.h", можно просто распечатать все эти длительности. Этот пример выводит:

Number of days = 16079[86400]s 
Number of hours = 12h 
Number of minutes = 35min 
Number of seconds = 34s 

[86400]s представляет единица duration, который имеет дни точности. Итак, 2014-01-09 - 16079 дней после 1970-01-01.