如何在 Windows 上获取 ISO 8601 格式的日期时间?

How to get datetime in ISO 8601 format on Windows?

使用 C++ 在 Windows 上获取 ISO8601 格式的日期时间的标准方法是什么?具体来说,我希望它的格式为:

2017-02-22T10:00:00.123-05:00 2017-02-22T10:00:00.123 >>> -05:00 <<< # how to print the offset?

我正在考虑合并 GetLocalTime and GetTimeZoneInformation 的输出,但这看起来很深奥。在 SO 上也有类似的问题,但是,我还没有找到一个以所需格式打印 UTC 偏移量的问题。有没有更好的方法?

也许是这样的。我们调用 GetLocalTimeGetTimeZoneInformation 然后将其传递给 returns 格式化字符串的函数。

这是快速编写的,除了观察它 returns 在我的机器上 现在 上的正确结果外,没有经过测试。它基于 SYSTEMTIME 有一个成员 Bias 的事实,其中 UTC = Localtime + BiasBias 以分钟为单位设置。因此,通过除以 60 并取其绝对值来获得小时数。然后我们以类似的方式获取分钟并根据 Bias > 0

设置符号
#include <Windows.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>

std::string format_system_time(const SYSTEMTIME& sys_time, const TIME_ZONE_INFORMATION& time_zone)
{
    std::ostringstream formatted_date_time;
    formatted_date_time << std::setfill('0');
    formatted_date_time << sys_time.wYear <<  "-" << std::setw(2) << sys_time.wMonth << "-" <<
        std::setw(2) << sys_time.wDay << "T" << std::setw(2) << sys_time.wHour << ":" <<
        std::setw(2) << sys_time.wMinute << ":" << std::setw(2) << sys_time.wSecond << "." <<
        std::setw(3) << sys_time.wMilliseconds;

    //UTC = localtime + bias; bias is in minutes
    int utc_offset_hours = time_zone.Bias / 60;
    int utc_offset_minutes = std::abs(time_zone.Bias - (utc_offset_hours * 60));
    char offset_sign = time_zone.Bias > 0 ? '-' : '+';
    formatted_date_time << offset_sign << std::setw(2) << std::abs(utc_offset_hours) << ":" << utc_offset_minutes;

    return formatted_date_time.str();
}

int main(int argc, char* argv[])
{
    SYSTEMTIME date_and_time;
    GetLocalTime(&date_and_time);

    TIME_ZONE_INFORMATION time_zone;
    GetTimeZoneInformation(&time_zone);

    auto& formatted_date_time = format_system_time(date_and_time, time_zone);

    return 0;
}

我认为 Windows 上没有适用于 c++ 的嵌入式解决方案。您可以获得的最接近的是 InternetTimeFromSystemTime,但仅记录为支持 RFC1123。

您可能需要自己编写 GetLocalTime + GetTimeZoneInformation + wsprintf(如果您不处理当前时间,则 GetTimeZoneInformationForYear)。

使用Howard Hinnant's free, open-source timezone library, which works on VS-2013 and later, but does require some installation:

#include "tz.h"
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    using namespace date;
    auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
    cout << format("%FT%T%Ez\n", zt);
}

这只是为我输出:

2017-02-22T17:29:03.859-05:00

格式说明符 %z 为您提供文档中所述的时区偏移量(例如 MSDN on strftime),但省略了“:”。您可以像这样使用它来将“:”放入您的字符串中:

struct tm tmNow;

time_t now = time(NULL);    // Get the current time
_localtime64_s(&tmNow, &now);

char bufferTime[26];
char bufferTimezoneOffset[6];
size_t tsizTime =  strftime(bufferTime, 26, "%Y-%m-%dT%H:%M:%S", &tmNow);   // The current time formatted "2017-02-22T10:00:00"
size_t tsizOffset =  strftime(bufferTimezoneOffset, 6, "%z", &tmNow);       // The timezone offset -0500
strncpy_s(&bufferTime[tsizTime], 26, bufferTimezoneOffset, 3);              // Adds the hour part of the timezone offset
bufferTime[tsizTime + 3] = ':';                                             // insert ':'
strncpy_s(&bufferTime[tsizTime + 4], 26, &bufferTimezoneOffset[3], 3);      // Adds the minutes part of the timezone offset
puts(bufferTime);   // Your output: "2017-02-22T10:00:00-05:00"

我省略了毫秒,因为据我所知它们不是本地时间的一部分。