C ++:将日期/时间字符串转换为tm结构

时间:2010-10-05 03:22:54

标签: c++ datetime locale

考虑这是this question的后续行动。从本质上讲,C ++日期/时间格式化设施似乎无可救药地被打破 - 以至于为了做一些简单的事情,如将日期/时间字符串转换为对象,你真的不得不求助于Boost.Datetime或者旧的C strftime / strptime设施。

问题是这些解决方案都不能直接使用嵌入特定iostream对象的C ++语言环境设置。 C工具使用全局C / POSIX语言环境设置,而Boost.Datetime中的I / O工具似乎完全绕过iostream语言环境设置,允许用户直接设置月份,工作日等的名称,而不管语言环境如何。

所以,我想要一些能够尊重特定I / O流上的语言环境设置的东西,这些设置允许我将字符串转换为struct tm。这似乎很容易,但我遇到了各个角落的障碍。起初,我注意到STL的一些实现提供了非标准的std::time_get::get函数,所以我决定实现类似的东西。基本上,我只是迭代格式字符串,每当我点击格式标志时,我会使用time_get工具之一(如get_monthname,get_weekday,get_year等)将输入字符串转换为struct tm。这似乎很容易,除了这些函数中的每一个都需要精确的迭代器范围。您无法转换"Monday,",它必须完全为"Monday",否则转换将失败。由于迭代器必须是istreambuf_iterator,因此您不能简单地向前扫描,因为每个增量都会更改流缓冲区中的获取位置。所以,基本上你必须首先迭代流,将每个字符复制到另一个 streambuffer,然后当你点击分隔符(如空格或逗号)时,使用第二个streambuffer和time_get工具。实际上,就好像C ++设计师竭尽全力使其尽可能烦人一样。

那么,有更简单的解决方案吗?大多数C ++程序员在需要将日期/时间字符串转换为对象时会做什么?我们是否只需要使用C设施,并且失去了在不同的iostream对象上出现的不同语言环境设置带来的好处?

3 个答案:

答案 0 :(得分:2)

Boost默认使用标准语言环境;你不必绕过任何东西:

#include "boost/date_time/gregorian/gregorian.hpp"
#include <iostream>
#include <sstream>
#include <ctime>

int main(){
  using namespace boost::gregorian;

  std::locale::global(std::locale(""));
  std::locale german("German_Germany");
  std::locale french("French_France");

  date d1(day_clock::local_day());
  date d2;
  std::stringstream ss("2002-May-01");

  std::cout << "Mine: " << d1 << " | ";
  ss >> d2;
  std::cout << d2 << '\n';

  std::cout.imbue(german);
  std::cout << "Germany: " << d1 << " | ";
  ss.imbue(german);
  ss << "2002-Mai-01";
  ss >> d2;
  std::cout << d2 << '\n';

  std::cout.imbue(french);
  std::cout << "France: " << d1 << " | " << d2 << '\n';

  std::tm t = to_tm(d1);
  std::cout << "tm: " << asctime(&t);
}

(当然,这些区域设置名称特定于Windows。)输出:

Mine: 2010-Oct-28 | 2002-May-01
Germany: 2010-Okt-28 | 2002-Mai-01
France: 2010-oct.-28 | 2002-mai-01
tm: Thu Oct 28 00:00:00 2010

答案 1 :(得分:0)

为什么不使用C库?它几乎可以在您的实现中使用,并且经过了很好的调试和测试。

如果它缺少某些功能,那么制作包装功能肯定会更容易,这会使你想要的时区工作。

答案 2 :(得分:0)

我总是尝试使用与语言环境无关的字符串来序列化数据。让生活更轻松。