当前位置: 首页 > 知识库问答 >
问题:

如何用boost::date_time读取ISO时区?

曹高轩
2023-03-14

我感到惊讶的是,boost::date_time似乎可以编写它无法读取的日期/时间字符串。

考虑以下示例代码:

#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>
#include <locale>

class PointTime : public boost::local_time::local_date_time {
    typedef boost::local_time::local_time_input_facet   input_facet_t;
    typedef boost::local_time::local_time_facet         output_face_t;

  public:
    static input_facet_t const s_input_facet;
    static output_face_t const s_output_facet;
    static std::locale const s_input_locale;
    static std::locale const s_output_locale;

  public:
    PointTime(std::string const& str);
};

PointTime::input_facet_t const PointTime::s_input_facet("%Y-%m-%dT%H:%M:%S%q", 1);
PointTime::output_face_t const PointTime::s_output_facet("%Y-%m-%dT%H:%M:%S%q",
    boost::local_time::local_time_facet::period_formatter_type(),
    boost::local_time::local_time_facet::special_values_formatter_type(),
    boost::local_time::local_time_facet::date_gen_formatter_type(),
    1);
std::locale const PointTime::s_input_locale(std::locale::classic(), &PointTime::s_input_facet);
std::locale const PointTime::s_output_locale(std::locale::classic(), &PointTime::s_output_facet);

PointTime::PointTime(std::string const& str) : boost::local_time::local_date_time(boost::local_time::not_a_date_time)
{
  std::istringstream is(str);
  is.imbue(s_input_locale);
  is >> *this;
  std::string s;
  is >> s;
  std::cout << "Left after parsing: \"" << s << "\"." << std::endl;
}

int main()
{
  std::string ts("2005-10-15T13:12:11-0700");
  std::cout << "ts = " << ts << std::endl;

  try
  {
    PointTime t(ts);
    std::cout.imbue(PointTime::s_output_locale);
    std::cout << "t =  " << t << std::endl;
  }
  catch (boost::bad_lexical_cast const& error)
  {
    std::cout << error.what() << std::endl;
  }

  return 0;
}

这将输出:

ts=2005-10-15T13:12:11-0700
解析后左:“-0700”。
t=2005-10-15T13:12:11Z

我理解它为什么这样做:%q格式被记录为“仅输出”,但我找不到实际读回此字符串的方法?!我应该怎么做?

共有2个答案

杨俊茂
2023-03-14

不幸的是,是的,这是目前的一个限制

添加了一些新标志,并覆盖了其他标志。输入系统仅支持特定标志,因此,并非所有用于输出的标志都与输入一起使用(我们目前正在努力纠正这种情况)。

同时,您也许能够利用 Boost Locale 的输入/输出功能:http://www.boost.org/doc/libs/1_55_0/libs/locale/doc/html/group__manipulators.html

潘涵煦
2023-03-14

最后,我使用了一个定制的方法来读回这些字符串。

我使用从< code > boost::POSIX _ time::ptime 派生的类来节省存储空间(超过从< code > boost::local _ time::local _ date _ time 派生的类),因为我不再使用boost-date-time的时区支持。

然而,当以字符串形式打印日期时,我希望它以“Z”结束,以表明它是祖鲁时间(UTC,GMT)而不是当地时间。我通过使用带有以“Z”结尾的格式字符串的输出方面实现了这一点。

PointTime类定义了一些(输入和输出)方面(即ISOInputFacetExtendedISOInputFacet和那些称为LLInputFacet的混合体,因为Linden Lab认为这是ISO标准并将其用于SecondLife(tm),呃。同样,ISOOutputFacetExtendedISOOutputFacetLLOutputFacet

该类实例化了六个方面中每一个的静态版本,因为我不想每次创建、读取或写入PointTime时都为一个方面调用new/ete。

这个函数的主要技巧是:

std::istream& operator>>(std::istream& is, PointTime& point_time)
{
  is >> static_cast<boost::posix_time::ptime&>(point_time);
  std::locale loc(is.getloc());
  if (std::has_facet<PointTime::InputFacet>(loc))
  {
    std::use_facet<PointTime::InputFacet>(loc).parse_timezone(is, point_time);
  }
  return is;
}

它窥视正在使用的输入方面,当它是从<code>PointTime::InputFacet</code>派生的输入方面时,它调用成员函数来解析可能的剩余时区。

下面给出了我编写的测试代码。也许它可以作为其他人的示例代码。

#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <iostream>
#include <locale>
#include <cassert>

class TZSignOrZ;

class PointTime : public boost::posix_time::ptime {
  public:
    struct InputFacet : public boost::posix_time::time_input_facet {
        InputFacet(char const* format, size_t ref_arg) : boost::posix_time::time_input_facet(format, ref_arg) { }
        static void parse_iso_timezone(std::istream& is, PointTime& point_time, bool colon);
        static void parse_hours_and_minutes(std::istream& is, PointTime& point_time, TZSignOrZ const& sign, bool colon);
        virtual void parse_timezone(std::istream& is, PointTime& point_time) const = 0;
    };

    struct ISOInputFacet : public InputFacet {
        ISOInputFacet(size_t ref_arg = 0) : InputFacet("%Y%m%dT%H%M%S%F", ref_arg) { }
        /*virtual*/ void parse_timezone(std::istream& is, PointTime& point_time) const;
    };

    struct ExtendedISOInputFacet : public InputFacet {
        ExtendedISOInputFacet(size_t ref_arg = 0) : InputFacet("%Y-%m-%d %H:%M:%S%F", ref_arg) { }
        /*virtual*/ void parse_timezone(std::istream& is, PointTime& point_time) const;
    };

    struct LLInputFacet : public InputFacet {
        LLInputFacet(size_t ref_arg = 0) : InputFacet("%Y-%m-%dT%H:%M:%S%F", ref_arg) { }
        /*virtual*/ void parse_timezone(std::istream& is, PointTime& point_time) const;
    };

    struct OutputFacet : public boost::posix_time::time_facet {
        OutputFacet(char const* format, size_t ref_arg) :
          boost::posix_time::time_facet(
              format, boost::posix_time::time_facet::period_formatter_type(),
              boost::posix_time::time_facet::special_values_formatter_type(),
              boost::posix_time::time_facet::date_gen_formatter_type(), ref_arg) { }
    };

    struct ISOOutputFacet : public OutputFacet {
        ISOOutputFacet(size_t ref_arg = 0) : OutputFacet("%Y%m%dT%H%M%S%FZ", ref_arg) { }
    };

    struct ExtendedISOOutputFacet : public OutputFacet {
        ExtendedISOOutputFacet(size_t ref_arg = 0) : OutputFacet("%Y-%m-%d %H:%M:%S%FZ", ref_arg) { }
    };

    struct LLOutputFacet : public OutputFacet {
        LLOutputFacet(size_t ref_arg = 0) : OutputFacet("%Y-%m-%dT%H:%M:%S%FZ", ref_arg) { }
    };

    static ISOInputFacet s_iso_input_facet;
    static ExtendedISOInputFacet s_extended_iso_input_facet;
    static LLInputFacet s_ll_input_facet;
    static ISOOutputFacet s_iso_output_facet;
    static ExtendedISOOutputFacet s_extended_iso_output_facet;
    static LLOutputFacet s_ll_output_facet;

  public:
    PointTime(void) { }
    PointTime(std::string const& str, InputFacet const& input_facet = s_extended_iso_input_facet);

    friend std::istream& operator>>(std::istream& os, PointTime& point_time);
};

PointTime::ISOInputFacet PointTime::s_iso_input_facet(1);
PointTime::ExtendedISOInputFacet PointTime::s_extended_iso_input_facet(1);
PointTime::LLInputFacet PointTime::s_ll_input_facet(1);
PointTime::ISOOutputFacet PointTime::s_iso_output_facet(1);
PointTime::ExtendedISOOutputFacet PointTime::s_extended_iso_output_facet(1);
PointTime::LLOutputFacet PointTime::s_ll_output_facet(1);

PointTime::PointTime(std::string const& str, InputFacet const& input_facet) : boost::posix_time::ptime(boost::posix_time::not_a_date_time)
{
  std::istringstream is(str);
  is.imbue(std::locale(std::locale::classic(), &input_facet));
  is >> *this;
}

std::istream& operator>>(std::istream& is, PointTime& point_time)
{
  is >> static_cast<boost::posix_time::ptime&>(point_time);
  std::locale loc(is.getloc());
  if (std::has_facet<PointTime::InputFacet>(loc))
  {
    std::use_facet<PointTime::InputFacet>(loc).parse_timezone(is, point_time);
  }
  return is;
}

struct TZSignOrZ {
  char c;
  friend std::istream& operator>>(std::istream& is, TZSignOrZ& sign)
  {
    sign.c = is.get();
    if (!is.good() || (sign.c != 'Z' && sign.c != '+' && sign.c != '-'))
    {
      if (!is.fail())
      {
        is.putback(sign.c);
      }
      throw std::runtime_error("Failed to read TZSignOrZ: first character after date-time is not a 'Z' or a sign.");
    }
    return is;
  }
  bool is_utc(void) const { return c == 'Z'; }
  bool is_negative(void) const { return c == '-'; }
};

struct TZColon {
  friend std::istream& operator>>(std::istream& is, TZColon& colon)
  {
    char c = is.get();
    if (!is.good() || c != ':')
      throw std::runtime_error("Failed to read TZColon: expected a colon between hours and minutes in time zone of date-time.");
    return is;
  }
};

struct TZTwoDigits {
  unsigned char val;
  friend std::istream& operator>>(std::istream& is, TZTwoDigits& digits)
  {
    char c1, c2;
    is >> std::noskipws >> c1 >> c2;
    if (!is.good() || !std::isdigit(c1) || !std::isdigit(c2))
      throw std::runtime_error("Failed to read TZTwoDigits: expected two digits for hours or minutes part in time zone of data-time.");
    digits.val = c2 - '0' + 10 * (c1 - '0');
    return is;
  }
};

void PointTime::InputFacet::parse_hours_and_minutes(std::istream& is, PointTime& point_time, TZSignOrZ const& sign, bool colon)
{
  TZTwoDigits hours, minutes;
  is >> hours;
  if (colon)
  {
    TZColon colon;
    is >> colon;
  }
  is >> minutes;
  boost::posix_time::time_duration duration(hours.val, minutes.val, 0, 0);
  if (sign.is_negative())
    point_time += duration;
  else
    point_time -= duration;
}

void PointTime::InputFacet::parse_iso_timezone(std::istream& is, PointTime& point_time, bool colon)
{
  if (!is.good())
    return; // Don't throw when the input stream is already bad.
  TZSignOrZ sign; 
  try
  {
    is >> sign;
  }
  catch (std::runtime_error const&)
  {
    // It is actually allowed to have no time zone.
    return;
  }
  parse_hours_and_minutes(is, point_time, sign, colon);
}

void PointTime::ISOInputFacet::parse_timezone(std::istream& is, PointTime& point_time) const
{
  parse_iso_timezone(is, point_time, false);
}

void PointTime::ExtendedISOInputFacet::parse_timezone(std::istream& is, PointTime& point_time) const
{
  parse_iso_timezone(is, point_time, true);
}

void PointTime::LLInputFacet::parse_timezone(std::istream& is, PointTime& point_time) const
{
  if (!is.good())
    return; // Don't throw when the input stream is already bad.
  TZSignOrZ sign;
  is >> sign;
  if (sign.is_utc())
    return;
  parse_hours_and_minutes(is, point_time, sign, false);
}

int main() 
{
  std::string test_strings[] = {
    "2014-09-10T00:12:34+0230",
    "2014-09-10T00:12:34.000567+0230",
    "2014-09-10T00:12:34.567+0230",
    "2014-09-10T21:32:34-0230",
    "2014-09-10T21:32:34.000567-0230",
    "2014-09-10T21:32:34.567-0230",
    "2014-09-10 00:12:34+02:30",
    "2014-09-10 00:12:34.000567+02:30",
    "2014-09-10 00:12:34.567+02:30",
    "2014-09-10 21:32:34-02:30",
    "2014-09-10 21:32:34.000567-02:30",
    "2014-09-10 21:32:34.567-02:30",
    "2014-09-10 00:12:34 hello!",
    "2014-09-10 00:12:34.000567***",
    "2014-09-10 00:12:34.567 hello!",
    "2014-09-10T00:12:34 +0230",
    "2014-09-10T00:12:34+ 0230",
    "2014-09-10T00:12:34+02 30",
    "2014-09-10T00:12:34 +02:30",
    "2014-09-10T00:12:34+ 02:30",
    "2014-09-10T00:12:34+02: 30",
    "2014-09-10T00:12:34+02 :30"
  };
  int const n = sizeof(test_strings) / sizeof(test_strings[0]);

  PointTime::InputFacet const* facets[] = {
    &PointTime::s_ll_input_facet,
    &PointTime::s_extended_iso_input_facet
  };

  std::cout << std::left << std::setw(32) << "INPUT" << "    " <<
  std::setw(40) << "LL input format" << "    " <<
  std::setw(40) << "Extended ISO input format" << std::endl;
  for (int i = 0 ; i < n ; ++i)
  {
    std::cout << std::left << std::setw(32) << test_strings[i];

    for (int j = 0; j < 2; ++j)
    {
      try
      {
        PointTime t;
        std::istringstream is(test_strings[i]);
        is.imbue(std::locale(std::locale::classic(), facets[j]));
        is >> t;
        std::string leftover;
        is >> std::noskipws;
        std::getline(is, leftover);
        std::ostringstream oss;
        oss.imbue(std::locale(std::locale::classic(), &PointTime::s_extended_iso_output_facet));
        oss << t;
        if (!leftover.empty())
        {
          oss << " [\"" << leftover << "\"]";
        }
        std::cout << " -- " << std::setw(40) << oss.str();
      }
      catch (boost::bad_lexical_cast const& error)
      {
        std::cout << " -- " << std::setw(40) << "invalid date-time";
      }
      catch (std::runtime_error const& error)
      {
        std::cout << " -- " << std::setw(40) << "invalid TZ";
      }
    }
    std::cout << std::endl;
  }

  return 0;
}

该程序的输出为:

INPUT                               LL input format                             Extended ISO input format               
2014-09-10T00:12:34+0230         -- 2014-09-09 21:42:34Z                     -- invalid TZ                              
2014-09-10T00:12:34.000567+0230  -- 2014-09-09 21:42:34.000567Z              -- invalid TZ                              
2014-09-10T00:12:34.567+0230     -- 2014-09-09 21:42:34.567000Z              -- invalid TZ                              
2014-09-10T21:32:34-0230         -- 2014-09-11 00:02:34Z                     -- invalid TZ                              
2014-09-10T21:32:34.000567-0230  -- 2014-09-11 00:02:34.000567Z              -- invalid TZ                              
2014-09-10T21:32:34.567-0230     -- 2014-09-11 00:02:34.567000Z              -- invalid TZ                              
2014-09-10 00:12:34+02:30        -- invalid TZ                               -- 2014-09-09 21:42:34Z                    
2014-09-10 00:12:34.000567+02:30 -- invalid TZ                               -- 2014-09-09 21:42:34.000567Z             
2014-09-10 00:12:34.567+02:30    -- invalid TZ                               -- 2014-09-09 21:42:34.567000Z             
2014-09-10 21:32:34-02:30        -- invalid TZ                               -- 2014-09-11 00:02:34Z                    
2014-09-10 21:32:34.000567-02:30 -- invalid TZ                               -- 2014-09-11 00:02:34.000567Z             
2014-09-10 21:32:34.567-02:30    -- invalid TZ                               -- 2014-09-11 00:02:34.567000Z             
2014-09-10 00:12:34 hello!       -- invalid TZ                               -- 2014-09-10 00:12:34Z [" hello!"]        
2014-09-10 00:12:34.000567***    -- invalid TZ                               -- 2014-09-10 00:12:34.000567Z ["***"]     
2014-09-10 00:12:34.567 hello!   -- invalid TZ                               -- 2014-09-10 00:12:34.567000Z [" hello!"] 
2014-09-10T00:12:34 +0230        -- invalid TZ                               -- 2014-09-10 00:12:34Z [" +0230"]         
2014-09-10T00:12:34+ 0230        -- invalid TZ                               -- invalid TZ                              
2014-09-10T00:12:34+02 30        -- invalid TZ                               -- invalid TZ                              
2014-09-10T00:12:34 +02:30       -- invalid TZ                               -- 2014-09-10 00:12:34Z [" +02:30"]        
2014-09-10T00:12:34+ 02:30       -- invalid TZ                               -- invalid TZ                              
2014-09-10T00:12:34+02: 30       -- invalid TZ                               -- invalid TZ                              
2014-09-10T00:12:34+02 :30       -- invalid TZ                               -- invalid TZ
 类似资料:
  • 我有一个这样的文件: [data.json] 如何通过解析此文件创建粒子向量。据我所知,我需要使用boop读取文件并将字符串(行)读入向量,然后解析向量的内容。 类粒子是这样的: 该类中省略了其他用于 get/set 的方法。 基本上,我想帮助创建一个

  • 问题内容: HTTP服务器向我发送JSON响应(字符串),如下所示: 我想将此“远程文件夹的树”与本地文件夹树(例如,包含本地文件位置的字符串向量)进行比较,因此我想在(string,vector(map(string ,string)))(我不知道是否可行)。 我正在开发一种工具来在本地文件夹和远程文件夹之间同步文件,因此我正在使用boost列出本地文件夹,并且我想将本地列表与远程列表(JSON

  • 一个HTTP服务器发送给我一个JSON响应(一个字符串),如下所示: 我想将这个“远程文件夹的树”与本地文件夹树(例如包含我的本地文件的位置的字符串向量)进行比较,所以我想在(string,vector ( map(string,string))(我不知道这是否可能)的地图上转换这个JSON。 我正在开发一个工具来同步本地和远程文件夹之间的文件,因此我正在使用boost列出本地文件夹,并且我想将本

  • 问题内容: 我目前正在尝试使用boost-asio的套接字API通过网络将一些JSON数据从客户端传输到服务器。我的客户基本上是这样做的: 在服务器端,我可以选择各种功能。我想使用JsonCpp解析接收到的数据。在研究JsonCpp API(http://jsoncpp.sourceforge.net/class_json_1_1_reader.html)时,我发现Reader可以在char数组或

  • 本文向大家介绍使用boost读取XML文件详细介绍,包括了使用boost读取XML文件详细介绍的使用技巧和注意事项,需要的朋友参考一下 boost读取XML文件 boost中提供了对配置文件读取的支持,它就是:property_tree。     basic_ptree 是property_tree的核心基础。其接口像std::list。可以执行很多基本的元素操作,比如使用begin()、end(

  • ISO 8601将持续时间格式声明为。例如,表示“3年、半个月和3分钟”。 有各种方法可以转换成unixtime/chrono::duration/whatever,但是我找到的所有解决方案都是用秒为单位的平均月和年持续时间,按照标准这是不正确的。相反,它应该取决于日期,例如< code>01 Feb P1M应该是< code>01 Mar ( 28天),而< code>01 Mar P1M应该是