使用std :: get_time将time-string转换为std :: time_t:结果错误

Tom*_*eus 6 c++ clang++

我想按照时间顺序对照片进行排序.因此,我从EXIF数据中提取时间作为字符串,然后我将其转换为std::time_t.但是我有时会得到错误的结果.我把问题简化为这个最小的例子.它有三个时间串,相隔一秒:

#include <vector>
#include <string>
#include <iostream>
#include <ctime>
#include <iomanip>
#include <sstream>

int main()
{
  std::vector<std::string> vec;

  vec.push_back("2016:07:30 09:27:06");
  vec.push_back("2016:07:30 09:27:07");
  vec.push_back("2016:07:30 09:27:08");

  for ( auto & i : vec )
  {
    struct std::tm tm;
    std::istringstream iss;
    iss.str(i);
    iss >> std::get_time(&tm,"%Y:%m:%d %H:%M:%S");

    std::time_t time = mktime(&tm);

    std::cout << i << " time = " << time << std::endl;
  }
}
Run Code Online (Sandbox Code Playgroud)

编译clang++ -std=c++14 test.cpp.

输出:

2016:07:30 09:27:06 time = 1469867226
2016:07:30 09:27:07 time = 1469863627
2016:07:30 09:27:08 time = 1469863628
Run Code Online (Sandbox Code Playgroud)

这显然是错误的,它们应该1分开,这只适用于最后两个?

编辑

由于clang std::get_time(和std::put_time)中似乎有一个错误,这是我的版本信息:

$ clang --version
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Run Code Online (Sandbox Code Playgroud)

And*_*ing 2

正如我在评论中所说,您的所有输出都是错误的。看来这是clang的一个bug。我在LLVM 项目的 Bugzilla 页面上进行了搜索,但没有找到任何结果。也许您想使用示例代码提交错误报告。

解决方法是手动解析字符串std::sscanf()并填充std::tm结构。以下代码对您的输入字符串执行此操作i请参阅ideone 的整个示例以及 ideone 的输出std::get_time()std::sscanf()方法。如果字符串不同,则根据您的需要调整该解决方案。

该解决方案使用%d:%d:%d %d:%d:%d格式字符串。您还可以使用%4d:%2d:%2d %2d:%2d:%2dwhich 只接受长度小于或等于%和之间的数字的数字d

输出:

2016:07:30 09:27:06 | sscanf() time =        1469870826
2016:07:30 09:27:06 | std::get_time() time = 1469870826
2016:07:30 09:27:07 | sscanf() time =        1469870827
2016:07:30 09:27:07 | std::get_time() time = 1469870827
2016:07:30 09:27:08 | sscanf() time =        1469870828
2016:07:30 09:27:08 | std::get_time() time = 1469870828
Run Code Online (Sandbox Code Playgroud)

代码:

#include <vector>
#include <string>
#include <iostream>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <cstring>

int main()
{
   std::vector<std::string> vec;

   vec.push_back("2016:07:30 09:27:06");
   vec.push_back("2016:07:30 09:27:07");
   vec.push_back("2016:07:30 09:27:08");

   for (auto & i : vec)
   {
      struct std::tm tm;

      /* std::sscanf() method: */
      std::memset(&tm, 0, sizeof(tm));
      if (6 != std::sscanf(i.c_str(), "%d:%d:%d %d:%d:%d",
                           &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
                           &tm.tm_hour, &tm.tm_min, &tm.tm_sec))
      {
         return -1;
      }

      /* correct the numbers according to:
       * see: http://en.cppreference.com/w/cpp/chrono/c/tm */
      --tm.tm_mon;
      tm.tm_year -= 1900;
      /* mktime determines if Daylight Saving Time was in effect
       * see: http://en.cppreference.com/w/cpp/chrono/c/mktime */
      tm.tm_isdst = -1;

      std::time_t time = std::mktime(&tm);

      std::cout << i << " | sscanf() time =        " << time << std::endl;

      /************************************************************/

      /* std::get_time() method: */
      std::istringstream iss;
      iss.str(i);
      iss >> std::get_time(&tm, "%Y:%m:%d %H:%M:%S");

      time = std::mktime(&tm);

      std::cout << i << " | std::get_time() time = " << time << std::endl;
   }
}
Run Code Online (Sandbox Code Playgroud)

有必要减去其中之一,tm_mon因为它从 0 开始。此外,该tm_year成员是自 1900 年以来的年份。请参阅此处的描述std::tm

此外,需要设置tm_isdst为 -1 以确定std::mktime()夏令是否有效。


要将std::time_tLinux 时间戳转换回给std::string定的格式:%Y:%m:%d %H:%M:%S您可以使用std::strftime()std ::localtime()请参阅 ideone 上的实例

输出:

time = 1469870826 | 2016:07:30 09:27:06
Run Code Online (Sandbox Code Playgroud)

代码:

#include <vector>
#include <string>
#include <iostream>
#include <ctime>

int main()
{
   char buff[20];
   time_t timestamp = 1469870826;
   std::strftime(buff, sizeof(buff), "%Y:%m:%d %H:%M:%S", std::localtime(&timestamp));
   std::string timeStr(buff);

   std::cout << "time = " << timestamp << " | " << timeStr;
}
Run Code Online (Sandbox Code Playgroud)