【问题标题】:Convert from UTC date string to Unix timestamp and back从 UTC 日期字符串转换为 Unix 时间戳并返回
【发布时间】:2021-11-07 04:33:11
【问题描述】:

如何将字符串“2021-11-15 12:10”UTC转换为Unix时间戳?

然后将两个小时添加到时间戳(如timestamp += 60*60*2)。

然后将生成的时间戳转换为 UTC 格式相同的字符串?

使用<chrono><ctime> 或库并不重要。

【问题讨论】:

  • 到目前为止你做了什么,把它贴在这里。
  • 生成的字符串总是指示比原始字符串晚 2 小时的时间是否不变量?如果是这样,那么最好不要将字符串解释为本地时间,而是 UTC。否则夏令时转换可能会引入错误。或者移动设备在解析和格式之间更改时区可能会引入错误。另一方面,那些“错误”可能正是您想要发生的。最好清楚地知道在这种极端情况下您希望发生什么。

标签: c++ c++17 chrono


【解决方案1】:

您可以使用 I/O 操纵器 std::get_timestd::put_time

例子:

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

int main() {
    std::istringstream in("2021-11-15 12:10"); // put the date in an istringstream
    
    std::tm t{};
    t.tm_isdst = -1; // let std::mktime try to figure out if DST is in effect

    in >> std::get_time(&t, "%Y-%m-%d %H:%M"); // extract it into a std::tm
    
    std::time_t timestamp = std::mktime(&t);   // get epoch

    timestamp += 2 * 60 *60;                   // add 2 hours

    std::tm utc = *std::gmtime(&timestamp);    // make a UTC std::tm
    std::tm lt = *std::localtime(&timestamp);  // make a localtime std::tm
    
    // print the results:
    std::cout << std::put_time(&utc, "%Y-%m-%d %H:%M") << '\n'
              << std::put_time(&lt, "%Y-%m-%d %H:%M") << '\n';
}

【讨论】:

  • @bolt Oups - 我忘了初始化t。我现在修好了。
  • 是的,没有{}tm 将填充“随机”数据。不客气!
  • 我担心std::tm t{}; 将在应该使用`tm.tm_isdst = -1; 时将.tm_isdst 成员和std::mktime(&amp;t); 归零。在您的时区,它可能是标准时间,在 2021-11-15,但在其他时区,它不是。使用 -1 可以让mktime() 弄清楚。
  • @chux-ReinstateMonica 是的,我同意。已添加。
  • @TedLyngmo Its OK "mktime函数转换分解时​​间,表示为当地时间...结构体tm_wday和tm_yday组件的原始值被忽略,其他组件不限于上述范围。...其他组件设置为表示指定的日历时间,但其值强制为上述范围。“ C17dr § 7.27.2.3 2
【解决方案2】:

由于最近编辑输入字符串表示 UTC 日期/时间,问题变得既简单又复杂。

  • 更简单的是,时区、夏令时和政治家没有复杂性。
  • 更复杂的是,没有可移植的 C 或 C++ 解决方案(C++20 之前),但有依赖于平台的解决方案。

此答案提出了 C++20 中新的可移植解决方案。但是,如果您没有 C++20,则存在一个 free, open-source, header-only solution that previews this part of C++20,它适用于 C++11/14/17 和所有平台。

#include <chrono>
#include <fmt>
#include <iostream>
#include <sstream>

std::string
test(std::string ts)
{
    using namespace std::chrono;

    std::istringstream in{std::move(ts)};
    sys_seconds tp;
    in >> parse("%F %H:%M", tp);
    return std::format("{:%F %H:%M}", tp + 2h);
}

int
main()
{
    std::cout << test("2021-11-15 12:10") << '\n';
}

以上是C++20的解决方案。 sys_seconds 类型是 Unix 时间戳。它计算自 1970-01-01 00:00:00 UTC 以来的秒数,不包括闰秒。如果你想要它的秒数,那就是tp.time_since_epoch().count()

只需对其进行解析,增加两个小时,然后对其进行格式化。从不考虑本地时区,因此不存在极端情况。这总是有效的。

例如,如果本地时区为“America/New_York”,输入字符串为“2021-11-07 00:10”,则输出字符串为“2021-11-07 02:10”。但是,如果此输入字符串与当前接受的答案一起使用,则输出字符串会少一个小时:“2021-11-07 01:10”。

要使用free, open-source, header-only solution

  1. #include &lt;fmt&gt; 替换为#include "date/date.h"
  2. 添加using namespace date;
  3. 将最后一行改为return format("%F %H:%M", tp + 2h);

【讨论】:

    猜你喜欢
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    • 2011-09-23
    相关资源
    最近更新 更多