使用boost date_time来解析和创建HTTP日期

时间:2010-05-15 01:22:04

标签: c++ http boost boost-date-time

我正在编写一种HTTP代理,所以我需要做三件事:

  1. 根据RFC 2616, sec 3.3
  2. 中指定的3种格式中的任何一种解析HTTP日期
  3. 将文件日期时间转换为HTTP日期字符串,然后
  4. 将日期输出为字符串。
  5. 作为参考,这些是我需要解析的日期时间的例子。我只输出第一种格式:

      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可以做到这一切,但是我遇到了一些问题。有没有人有代码可以做到这一点?也许我并没有熟练使用谷歌,但我找不到一个如何在任何地方提升的例子。

    感谢您的帮助!

    更新:我有一个解决方案,但第二个解析器有错误的一年(我猜因为它是一个2位数的年份),最后一个解析器给出了一个例外(见下面的输出)。

    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 个答案:

答案 0 :(得分:6)

我认为你不需要走那么远就可以到达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)) {..}

答案 1 :(得分:4)

这是我创建的DateTime类,可以满足我的需要。也许其他人会使用它。此代码在公共领域。我欢迎任何评论。

顺便说一句,显然std :: locale接受一个facet指针,然后在完成它时删除它,所以不需要删除它(事实上,删除它会破坏它)。

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);
}