簡體   English   中英

如何使用boost :: date_time讀取ISO時區?

[英]How to read an ISO timezone with boost::date_time?

我很驚訝似乎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格式被記錄為“僅輸出”,但我找不到實際讀回這個字符串的方法?! 我該怎么做?

令人遺憾的是,這是目前的限制

添加了一些新標記,其他標記被覆蓋。 輸入系統僅支持特定標志,因此, 並非所有用於輸出的標志都可以使用輸入 (我們目前正在努力糾正這種情況)。

同時,您可以利用Boost Locale的輸入/輸出工具: http//www.boost.org/doc/libs/1_55_0/libs/locale/doc/html/group__manipulators.html

最后,我使用自定義方法來回讀這些字符串。

我使用從boost::posix_time::ptime派生的類來節省存儲空間(從boost::local_time::local_date_time派生)因為我不再使用boost-date-time的時區支持了。

但是,當將日期打印為字符串時,我希望它以“Z”結束,以明確它是在祖魯時間(UTC,GMT)而不是當地時間。 我通過使用帶有以'Z'結尾的格式字符串的輸出面來實現這一點。

PointTime類定義了一些(輸入和輸出)方面(即ISOInputFacetExtendedISOInputFacet以及那些名為LLInputFacet的組合,因為Linden Lab認為這是ISO標准並將其用於SecondLife(tm),同樣, ISOOutputFacetExtendedISOOutputFacetLLOutputFacet

該類實例化六個方面中每個方面的靜態版本,因為每次創建,讀取或寫入PointTime時,我都不想為方面調用new / delete。

主要技巧是在這個功能:

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

它隱藏了正在使用的輸入方面,當它是從PointTime::InputFacet派生的PointTime::InputFacet時,它調用一個成員函數來解析可能的剩余時區。

我寫的測試代碼如下。 也許它可以作為其他人的示例代碼。

#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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM