C++字符串到日期时间函数

huangapple go评论75阅读模式
英文:

C++ String to DateTime Functions

问题

来自C#的我对C++中的日期时间功能感到有些迷茫。我只是想将格式为2023-01-12T07:00:00+08:00的字符串转换为自2023年1月1日UTC以来的秒数。

以及反向操作,即将自2023年初以来的秒数整数转换为格式为"%Y-%m-%dT%H:%M:%S%z"的字符串。任何代码或指向正确方向的指针都将不胜感激。

已经尝试了使用chrono和time_t的各种选项,似乎可以工作:

std::time_t getTime(const std::string& dateTime) {
    std::chrono::sys_time<std::chrono::seconds> tTime;
    std::istringstream stream(dateTime);
    std::chrono::from_stream(stream, "%Y-%m-%dT%H:%M:%S%z", tTime);
    return std::chrono::system_clock::to_time_t(tTime);
}

const time_t EPOCH_2023 = getTime("2023-01-01T00:00:00+00:00");

int stringToIntTime(const std::string& dateTime) {
    return static_cast<int>(getTime(dateTime) - EPOCH_2023);
}

要获取整数值。

但我对如何执行反向操作毫无头绪。

英文:

Coming from C# I'm a bit lost with the datetime functionality in C++. I am simply looking to convert from a string in the format 2023-01-12T07:00:00+08:00 to the number of seconds since 1-1-2023 UTC.

And the reverse, i.e. an int of the number of seconds since the start of 2023 to a string in the format "%Y-%m-%dT%H:%M:%S%z". Any code or pointers in the right direction would be greatly appreciated.

Have tried various options using chrono and time_t which seems to work:

std::time_t getTime(const std::string&amp; dateTime) {
    std::chrono::sys_time&lt;std::chrono::seconds&gt; tTime;
    std::istringstream stream(dateTime);
    std::chrono::from_stream(stream, &quot;%Y-%m-%dT%H:%M:%S%z&quot;, tTime);
    return std::chrono::system_clock::to_time_t(tTime);
}

const time_t EPOCH_2023 = getTime(&quot;2023-01-01T00:00:00+00:00&quot;);

int stringToIntTime(const std::string&amp; dateTime) {
    return static_cast&lt;int&gt;(getTime(dateTime) - EPOCH_2023);
}

to get the int.

But I haven't a clue on doing the reverse.

答案1

得分: 2

以下是我推荐的代码:

#include <chrono>
#include <format>
#include <iostream>
#include <sstream>

using namespace std::chrono_literals;
constexpr std::chrono::sys_seconds EPOCH_2023 = std::chrono::sys_days{2023y/01/01};

int stringToIntTime(const std::string& dateTime)
{
    using namespace std;
    using namespace std::chrono;

    sys_seconds tTime;
    istringstream stream(dateTime);
    stream >> parse("%FT%T%Ez", tTime);
    return (tTime - EPOCH_2023)/1s;
}

std::string intToStringTime(int i)
{
    using namespace std;
    using namespace std::chrono;

    sys_seconds t = EPOCH_2023 + seconds{i};
    return format("{:%FT%T%Ez}", zoned_time{"Etc/GMT-8", t});
}

int main()
{
    using namespace std;

    int i = stringToIntTime("2023-01-12T07:00:00+08:00");
    string s = intToStringTime(i);
    cout << i << '\n';
    cout << s << '\n';
}

这段代码的输出应该是:

946800
2023-01-12T07:00:00+08:00

我已经对stringToIntTime函数进行了一些简化:

  • 你的 EPOCH_2023 常量可以更高效地存储为 sys_seconds 类型,而不是字符串,并使其为 constexpr。在目标代码中,这将只是一个整数文字,表示从你的纪元到1970年01月01日的system_clock纪元的秒数。

  • stringToIntTime 是正确的,但我将其简化为一个函数,并使用parse代替from_stream,以获得稍微更清晰的语法。parse是一个稍微高级的API。

  • 还要注意在格式化字符串中使用 %Ez 替代 %z。前者包括UTC偏移的小时和分钟之间的 : 分隔符。

  • 无需通过C API使用 time_t。可以直接从解析的UTC时间 tTime 中减去你的纪元。这将得到自你的纪元以来的秒数。要将其转换为 int,只需除以1秒。

  • intToStringTime 从将 int 转换为秒开始,然后将其添加到你的纪元中。这会给 t 一个 sys_seconds 类型,具有自 system_clock 纪元以来的秒数值。

  • 最后,只需格式化 t,使用具有 +08:00 UTC偏移的时区,并使用所需的格式。请注意在名称中使用 -8 来获得 +8 的偏移量。这只是IANA继承的POSIX怪癖。如果需要其他时区,只需将其替换为 "Etc/GMT-8"

  • 注意使用 %T,它是 %H:%M:%S 的快捷方式,以及 %F,它是 %Y-%m-%d 的快捷方式。

英文:

Here is what I recommend:

#include &lt;chrono&gt;
#include &lt;format&gt;
#include &lt;iostream&gt;
#include &lt;sstream&gt;

using namespace std::chrono_literals;
constexpr std::chrono::sys_seconds EPOCH_2023 = std::chrono::sys_days{2023y/01/01};

int
stringToIntTime(const std::string&amp; dateTime)
{
    using namespace std;
    using namespace std::chrono;

    sys_seconds tTime;
    istringstream stream(dateTime);
    stream &gt;&gt; parse(&quot;%FT%T%Ez&quot;, tTime);
    return (tTime - EPOCH_2023)/1s;
}

std::string
intToStringTime(int i)
{
    using namespace std;
    using namespace std::chrono;

    sys_seconds t = EPOCH_2023 + seconds{i};
    return format(&quot;{:%FT%T%Ez}&quot;, zoned_time{&quot;Etc/GMT-8&quot;, t});
}

int
main()
{
    using namespace std;

    int i = stringToIntTime(&quot;2023-01-12T07:00:00+08:00&quot;);
    string s = intToStringTime(i);
    cout &lt;&lt; i &lt;&lt; &#39;\n&#39;;
    cout &lt;&lt; s &lt;&lt; &#39;\n&#39;;
}

Which should output:

946800
2023-01-12T07:00:00+08:00

I've taken the liberty of simplifying your stringToIntTime somewhat:

  • Your EPOCH_2023 constant can be made more efficient by storing it in a sys_seconds type as opposed to a string, and making it constexpr. In the object code this will just be a integral literal which is the count of seconds between your epoch and the system_clock epoch of 1970-01-01.

  • stringToIntTime is correct, but I've simplified it down to one function and used parse in place of from_stream just for slightly cleaner syntax. parse is a slightly higher level API.

  • Also note the use of %Ez in place of %z. The former includes the : separator between the hours and minutes of the UTC offset.

  • There's no need to go through the C API with time_t. One can just subtract the parsed UTC time tTime from your epoch. This results in seconds since your epoch. To convert that to int, just divide by 1 second.

  • intToStringTime starts with converting the int to seconds and adding that to your epoch. This gives t the type sys_seconds and the value of a time_point with seconds since the system_clock epoch.

  • Finally just format t, using a time zone with the +08:00 UTC offset, using the desired format. Note the use of -8 in the name to give +8 for the offset. This is simply POSIX weirdness that IANA inherits. If some other time zone is desired, just sub that in for &quot;Etc/GMT-8&quot;.

  • Note the use of %T which is a shortcut for %H:%M:%S and %F which is a shortcut for %Y-%m-%d.

答案2

得分: 0

最好的方式可能是使用 sscanf_s(自 C11 起在 stdio.h 中可用)或 strptime(POSIX 标准)将字符串转换为单个值或 tm 类型(time.h)。然后,您可以使用 mktime(time.h)将其转换回 time_t 类型。然后只需将它们相减。 https://stackoverflow.com/questions/11213326/how-to-convert-a-string-variable-containing-time-to-time-t-type-in-c

英文:

The best way is probably to use sscanf_s (stdio.h since C11) or strptime (POSIX standard) to convert the string into either individual values or a tm type (time.h), respectively. From there you can use mktime (time.h) to get back a time_t type. Then just subtract them. https://stackoverflow.com/questions/11213326/how-to-convert-a-string-variable-containing-time-to-time-t-type-in-c

huangapple
  • 本文由 发表于 2023年1月9日 10:31:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定