如何在 C++ 中构建 ISO 8601 日期时间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9527960/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:55:53  来源:igfitidea点击:

How do I construct an ISO 8601 datetime in C++?

c++qtazure

提问by chikuba

I'm working with the Azure REST API and they are using this to create the request body for table storage:

我正在使用 Azure REST API,他们正在使用它来创建表存储的请求正文:

DateTime.UtcNow.ToString("o")

Which produces:

其中产生:

2012-03-02T04:07:34.0218628Z

2012-03-02T04:07:34.0218628Z

It is called "round-trip" and apparently it's an ISO standard (see http://en.wikipedia.org/wiki/ISO_8601) but I have no idea how to replicate it after reading the wiki article.

它被称为“往返”,显然它是一个 ISO 标准(参见http://en.wikipedia.org/wiki/ISO_8601),但我不知道如何在阅读 wiki 文章后复制它。

Does anyone know if Boosthas support for this, or possibly Qt?

有谁知道Boost是否支持这个,或者可能是Qt吗?

回答by strcat

If the time to the nearest second is precise enough, you can use strftime:

如果到最接近秒的时间足够精确,您可以使用strftime

#include <ctime>
#include <iostream>

int main() {
    time_t now;
    time(&now);
    char buf[sizeof "2011-10-08T07:07:09Z"];
    strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now));
    // this will work too, if your compiler doesn't support %F or %T:
    //strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
    std::cout << buf << "\n";
}

If you need more precision, you can use Boost:

如果您需要更高的精度,可以使用 Boost:

#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>

int main() {
    using namespace boost::posix_time;
    ptime t = microsec_clock::universal_time();
    std::cout << to_iso_extended_string(t) << "Z\n";
}

回答by Gillespie

Using the datelibrary (C++11):

使用日期库(C++11):

template <class Precision>
string getISOCurrentTimestamp()
{
    auto now = chrono::system_clock::now();
    return date::format("%FT%TZ", date::floor<Precision>(now));
}

Example usage:

用法示例:

cout << getISOCurrentTimestamp<chrono::seconds>();
cout << getISOCurrentTimestamp<chrono::milliseconds>();
cout << getISOCurrentTimestamp<chrono::microseconds>();

Output:

输出:

2017-04-28T15:07:37Z
2017-04-28T15:07:37.035Z
2017-04-28T15:07:37.035332Z

回答by Rahim Khoja

I should point out I am a C++ newb.

我应该指出我是一个 C++ 新手。

I needed string with a UTC ISO 8601 formatted date and time that included milliseconds. I did not have access to boost.

我需要带有 UTC ISO 8601 格式的日期和时间(包括毫秒)的字符串。我没有权限提升。

This is more of a hack than a solution, but it worked well enough for me.

这与其说是解决方案,不如说是一种黑客攻击,但它对我来说效果很好。

std::string getTime()
{
    timeval curTime;

    gettimeofday(&curTime, NULL);

    int milli = curTime.tv_usec / 1000;
    char buf[sizeof "2011-10-08T07:07:09.000Z"];
    strftime(buf, sizeof buf, "%FT%T", gmtime(&curTime.tv_sec));
    sprintf(buf, "%s.%dZ", buf, milli);

    return buf;
}

The output looks like: 2016-04-13T06:53:15.485Z

输出看起来像:2016-04-13T06:53:15.485Z

回答by vines

Boost has a libraryfor this.

Boost 有一个用于此的

I.e. posix_timehas the from_iso_string()and to_iso_string()functions.

posix_time具有from_iso_string()to_iso_string()功能。

回答by Chris Browet

In Qt, that would be:

在 Qt 中,这将是:

QDateTime dt = QDateTime::currentDateTime();
dt.setTimeSpec(Qt::UTC);  // or Qt::OffsetFromUTC for offset from UTC
qDebug() << QDateTime::currentDateTime().toString(Qt::ISODate);

回答by Danie Bruwer

OK so I've modified a few solutions that I've found as came up with the following :

好的,所以我修改了一些我发现的解决方案,如下所示:

static QString getTimeZoneOffset()
{
    QDateTime dt1 = QDateTime::currentDateTime();
    QDateTime dt2 = dt1.toUTC();
    dt1.setTimeSpec(Qt::UTC);

int offset = dt2.secsTo(dt1) / 3600;
if (offset >= 0)
    return QString("%1").arg(offset).rightJustified(2, '0',true).prepend("+");
return QString("%1").arg(offset).rightJustified(2, '0',true);
}

Then to easily format a date ( yyyy-MM-dd'T'HH:mm:ss.SSSZ) :

然后轻松格式化日期(yyyy-MM-dd'T'HH:mm:ss.SSSZ):

static QString toISO8601ExtendedFormat(QDateTime date)
{
    QString dateAsString = date.toString(Qt::ISODate);
    QString timeOffset =  Define::getTimeZoneOffset();
    qDebug() << "dateAsString :" << dateAsString;
    qDebug() << "timeOffset :" << timeOffset;
    timeOffset = QString(".000%1%2").arg(timeOffset).arg("00");
    qDebug() << "timeOffset replaced :" << timeOffset;
    if(dateAsString.contains("Z",Qt::CaseInsensitive))
        dateAsString = dateAsString.replace("Z",timeOffset);
    else
        dateAsString = dateAsString.append(timeOffset);
        qDebug() << "dateAsString :" << dateAsString;
    return dateAsString;
}

For example GMT +2 would look like this : 2013-10-14T00:00:00.000+0200

例如 GMT +2 看起来像这样: 2013-10-14T00:00:00.000+0200

回答by Joma

Tested in Visual C++, GNU C++, Emscripten

在 Visual C++、GNU C++、Emscripten 中测试

#include <ctime>
#include <chrono>
#include <iostream> 
#include <locale>  

#if defined (_WIN32) 
#define WINDOWSLIB 1
#elif defined (__APPLE__)//iOS, Mac OS
#define MACOSLIB 1
#elif defined (__LINUX__) || defined(__gnu_linux__) || defined(__linux__) || defined(__linux) || defined(linux)//_Ubuntu - Fedora - Centos - RedHat
#define LINUXLIB 1
#elif defined (__EMSCRIPTEN__)
#define EMSCRIPTENLIB 1
#endif

#define WriteLine(data)std::cout<< data <<std::endl;
typedef std::string String;

String CurrentISO8601DateTime(bool toUTC=true)
{
    using namespace std::chrono;
    system_clock::time_point now = system_clock::now();
    time_t timet = system_clock::to_time_t(now);
    std::tm tm{};
    String localeStr = setlocale(LC_ALL, nullptr);
    setlocale(LC_ALL, u8"");
    String format = String(u8"%FT%T.").append(std::to_string(duration_cast<milliseconds>(now.time_since_epoch()).count() % static_cast<long long>(1000)));
    if (toUTC)
    {
#ifdef WINDOWSLIB
        gmtime_s(&tm, &timet);
#elif LINUXLIB
        gmtime_r(&timet, &tm);
#elif EMSCRIPTENLIB
        gmtime_r(&timet, &tm);
#endif
        format = format.append(u8"Z");
    }
    else
    {
#ifdef WINDOWSLIB
        localtime_s(&tm, &timet);
#elif LINUXLIB
        localtime_r(&timet, &tm);
#elif EMSCRIPTENLIB
        localtime_r(&timet, &tm);
#endif
        format.append(u8"%z");
    }
    String result = String(255, 0);
    const size_t length = std::strftime(&result[0], result.size(), format.c_str(), &tm);
    result.resize(length);
    setlocale(LC_ALL, localeStr.c_str());
    return result;
}

#define ConsoleWriteLn(data) std::cout<< data <<std::endl;

int main()
{
    ConsoleWriteLn(u8"UTC  : " + CurrentISO8601DateTime());
    ConsoleWriteLn(u8"LOCAL: " + CurrentISO8601DateTime(false));
}



Results结果

UTC : 2020-04-12T17:00:18.632Z
LOCAL: 2020-04-12T12:00:18.633-0500

UTC : 2020-04-12T17:00:18.632Z
本地: 2020-04-12T12:00:18.633-0500

You can deserialize normally with Json.NET

您可以使用Json.NET正常反序列化

回答by chikuba

Did it like this:

是不是这样的:

using namespace boost::posix_time;
ptime t = microsec_clock::universal_time();
qDebug() << QString::fromStdString(to_iso_extended_string(t) + "0Z"); // need 7 digits