Используйте boost date_time для разбора и создания HTTP-дат
Я пишу своего рода HTTP-прокси, поэтому мне нужно уметь делать 3 вещи:
- Разобрать HTTP-дату по любому из 3 форматов, указанных в RFC 2616, с. 3.3,
- Преобразовать дату-время файла в строку HTTP-даты и
- Вывести дату в строку.
Для справки, тезисы являются примерами даты и времени, которые мне нужно проанализировать. Я выведу только первый формат:
Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
Я почти уверен, что Boost date_time может сделать все это, но у меня возникли некоторые проблемы с номером 1. У кого-нибудь уже есть код для этого? Возможно, я не пользуюсь Google умело, но я не могу найти пример того, как сделать это с Boost где-нибудь.
Спасибо за любую помощь!
ОБНОВЛЕНИЕ: у меня есть решение, но у второго синтаксического анализатора неправильный год (я полагаю, потому что это год с двумя цифрами), и последний синтаксический анализатор дает исключение (см. Вывод ниже).
try
{
// output time now in GMT
// format we want: Sun, 06 Nov 1994 08:49:37 GMT
boost::local_time::local_date_time t(boost::local_time::local_sec_clock::local_time(boost::local_time::time_zone_ptr()));
boost::local_time::local_time_facet* lf(new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT"));
std::cout.imbue(std::locale(std::cout.getloc(), lf));
std::cout << t << std::endl;
// get a file mod time into the correct format
boost::filesystem::path p("../code/main.cpp");
boost::posix_time::ptime pt = boost::posix_time::from_time_t(
boost::filesystem::last_write_time(p));
boost::local_time::local_date_time t2(pt, boost::local_time::time_zone_ptr());
std::cout << t2 << std::endl;
std::stringstream ss;
ss.exceptions(std::ios_base::failbit);
// input date-time
boost::local_time::local_time_input_facet* lif1(new boost::local_time::local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT"));
ss.imbue(std::locale(std::locale::classic(), lif1));
ss.str("Sun, 06 Nov 1994 08:49:37 GMT");
ss >> t;
std::cout << t << std::endl;
boost::local_time::local_time_input_facet* lif2(new boost::local_time::local_time_input_facet("%A, %d-%b-%y %H:%M:%S GMT"));
ss.imbue(std::locale(std::locale::classic(), lif2));
ss.str("Sunday, 06-Nov-94 08:49:37 GMT");
ss >> t;
std::cout << t << std::endl;
boost::local_time::local_time_input_facet* lif3(new boost::local_time::local_time_input_facet("%a %b %e %H:%M:%S %Y"));
ss.imbue(std::locale(std::locale::classic(), lif3));
ss.str("Sun Nov 6 08:49:37 1994");
ss >> t;
std::cout << t << std::endl;
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
Выход:
Sat, 15 May 2010 03:01:13 GMT
Sat, 15 May 2010 03:01:01 GMT
Sun, 06 Nov 1994 08:49:37 GMT
Sat, 06 Nov 2094 08:49:37 GMT
Exception: Parse failed. No match found for ''
2 ответа
Я не думаю, что вам нужно заходить так далеко и тянуться к Boost:) Вы можете обойтись без простого кода на C:
static const char format[] = "%a, %d %b %Y %H:%M:%S %Z"; // rfc 1123
struct tm tm;
bzero(&tm, sizeof(tm));
if (strptime(str, format, &tm)) {..}
Вот класс DateTime, который я создаю, который делает то, что мне нужно. Может быть, кто-то еще будет использовать это. Этот код в свободном доступе. Я приветствую любые комментарии.
Между прочим, очевидно, что std:: locale берет указатель на фасет, а затем удаляет его, когда он завершает работу с ним, поэтому нет необходимости удалять его (на самом деле удаление его нарушает все).
datetime.h:
// $Id$
#ifndef _DATETIME_H_
#define _DATETIME_H_
#include <string>
#include "common.h"
#include <boost/date_time/local_time/local_time.hpp>
class DateTime
{
public:
DateTime();
DateTime(const std::string& path);
// return datetime string
std::string str();
// update datetime from file mod date
std::string from_file(const std::string& path);
// parse datetime string
void parse(const std::string& dt);
// boolean equal operator
friend bool operator==(const DateTime& left, const DateTime& right);
private:
boost::local_time::local_date_time m_dt;
};
#endif // _DATETIME_H_
datetime.cpp:
// $Id$
#include <sstream>
#include "common.h"
#include <boost/date_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/operations.hpp>
#include "datetime.h"
DateTime::DateTime()
:m_dt(boost::local_time::local_sec_clock::local_time(boost::local_time::time_zone_ptr()))
{
}
DateTime::DateTime(const std::string& path)
:m_dt(boost::local_time::local_sec_clock::local_time(boost::local_time::time_zone_ptr()))
{
from_file(path);
}
std::string DateTime::str()
{
std::string result;
boost::local_time::local_time_facet* lf(new boost::local_time::local_time_facet("%a, %d %b %Y %H:%M:%S GMT"));
try
{
std::stringstream ss;
ss.imbue(std::locale(ss.getloc(), lf));
ss << m_dt;
result = ss.str();
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
return result;
}
std::string DateTime::from_file(const std::string& path)
{
try
{
boost::filesystem::path p(path);
boost::posix_time::ptime pt = boost::posix_time::from_time_t(
boost::filesystem::last_write_time(p));
m_dt = boost::local_time::local_date_time(pt, boost::local_time::time_zone_ptr());
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
return str();
}
void DateTime::parse(const std::string& dt)
{
boost::local_time::local_time_input_facet* lif(new boost::local_time::local_time_input_facet("%a, %d %b %Y %H:%M:%S GMT"));
std::stringstream ss(dt);
ss.imbue(std::locale(std::locale::classic(), lif));
ss >> m_dt;
}
bool operator==(const DateTime& left, const DateTime& right)
{
return (left.m_dt == right.m_dt);
}