【问题标题】:Converting tm to time_t on windows in UTC - _mkgmtime returning -1在 UTC 的窗口上将 tm 转换为 time_t - _mkgmtime 返回 -1
【发布时间】:2020-12-01 06:36:36
【问题描述】:

我正在尝试在 Windows 上将 UTC ECMA date format strings 解析为 std::chrono::system_clock::time_point

我的计划:

  1. 使用scanf 将字符串加载到struct tm
  2. 使用_mkgmtime 将其转换为time_t(我为此使用_mkgmtime,因为它使用UTC 时间,不像mktime 之类的使用当地时间)。
  3. 使用std::chrono::system_clock::from_time_t 转换为time_point

但是,第 2 步总是为我返回 -1,给我第 3 步的虚假值。

tm 结构似乎有效,所以我不确定自己做错了什么。

#include <chrono>
#include <iostream>

using namespace std;

int main() {
  string timeStr = "2020-12-01T06:06:48Z";

  struct tm tm = {0};
  float s;
  if (sscanf_s(timeStr.c_str(), "%d-%d-%dT%d:%d:%fZ", &tm.tm_year, &tm.tm_mon,
               &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &s) == 6) {
    tm.tm_sec = static_cast<int>(s);

    time_t t = _mkgmtime(&tm);
    cout << "YEAR: " << tm.tm_year << endl;  // 2020
    cout << "MON:  " << tm.tm_mon << endl;   // 12
    cout << "MDAY: " << tm.tm_mday << endl;  // 1
    cout << "HOUR: " << tm.tm_hour << endl;  // 6
    cout << "MIN:  " << tm.tm_min << endl;   // 6
    cout << "SEC:  " << tm.tm_sec << endl;   // 48
    cout << "TIME: " << t << endl;           // -1

    // TODO once this is solved:
    auto tp = chrono::system_clock::from_time_t(t);
  }
}

编译器为 MSVC 2019、C++17、x64。我无法升级到 C++20,否则我会为此使用新的计时工具。

【问题讨论】:

  • 旁注:起草了大部分 chrono 内容的 Howard Hinnant 发布了很多将其转化为 C++20 into the wild years before C++20 的内容。您可能会从 C++17 中的这些第三方库中获得所需的支持,并且在将来升级到 C++20 时几乎已做好准备。
  • 不是“那个”问题,但== 6 会比!= EOF 工作得更好。
  • @user4581301 感谢您的资源 - 这是一种一次性的方法,我不一定要包含整个第三方库来执行此操作。不过,我一定会仔细检查的。
  • bug: 2020 需要减去 1900。tm_year 是自 1900 年以来的年数。
  • @user4581301 哦,看这个太久了。谢谢。将其发布为答案,我会接受。

标签: c++ windows parsing chrono


【解决方案1】:

tm 结构中,成员tm_year is the number of years since 1900。在 2020 年喂食意味着您实际上是在提供 3920 年。

看起来_mkgmtime 讨厌那一年。在我的系统上_mkgmtime64 似乎也不起作用。它应该适合 64 位 time_t,但绝对超出 32 位版本的范围。我找不到明确的、记录在案的 3920 被拒绝的原因或功能放弃的截止点。确保您拥有 64 位 time_t

但在这种情况下,这些都不重要,因为我们想要 2020 年。添加

tm.tm_year -= 1900;
tm.tm_mon -= 1; // valid range 0 to 11, not 1 to 12

在转换之前会解决问题。

【讨论】:

    【解决方案2】:

    这是它在 C++20 中的样子:

    #include <chrono>
    #include <iostream>
    #include <sstream>
    
    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
        string timeStr = "2020-12-01T06:06:48Z";
        istringstream in{timeStr};
        system_clock::time_point tp;
        in >> parse("%FT%TZ", tp);
        cout << tp << '\n';  // 2020-12-01 06:06:48.000000
    }
    

    使用 C++20 &lt;chrono&gt; preview library,只需添加 #include "date/date.h"using namespace date;,它现在可以在 C++11/14/17 中使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-06
      • 2014-02-02
      • 2016-05-23
      • 2012-06-22
      • 2019-04-12
      • 2018-06-04
      • 2021-07-21
      相关资源
      最近更新 更多